当前位置:  开发笔记 > IOS > 正文

在Objective-C中将消息发送到nil

如何解决《在Objective-C中将消息发送到nil》经验,为你挑选了10个好方法。

作为正在阅读Apple的Objective-C 2.0文档的Java开发人员:我想知道" 向nil发送消息 "意味着什么 - 更不用说它实际上有用了什么.摘自文档:

Cocoa中有几种模式可以利用这一事实.从消息返回到nil的值也可能是有效的:

如果该方法返回一个对象,任何指针类型,任何大小小于或等于sizeof(void*),float,double,long double或long long的整数标量,则发送给nil的消息返回0 .

如果该方法返回一个结构,如Mac OS X ABI函数调用指南所定义的那样在寄存器中返回,那么发送给nil的消息将为数据结构中的每个字段返回0.0.其他结构数据类型不会用零填充.

如果该方法返回除上述值类型之外的任何内容,则发送到nil的消息的返回值是未定义的.

Java是否让我的大脑无法解释上面的解释?或者是否有一些我想念的东西会让它像玻璃一样清晰?

我确实在Objective-C中得到了消息/接收器的概念,我只是对接收器碰巧感到困惑nil.



1> Michael Buck..:

好吧,我认为可以用一个非常人为的例子来描述.假设您在Java中有一个方法打印出ArrayList中的所有元素:

void foo(ArrayList list)
{
    for(int i = 0; i < list.size(); ++i){
        System.out.println(list.get(i).toString());
    }
}

现在,如果你这样调用那个方法:someObject.foo(NULL); 当你试图访问列表时,你可能会得到一个NullPointerException,在这种情况下是对list.size()的调用; 现在,您可能永远不会像这样使用NULL值调用someObject.foo(NULL).但是,您可能从一个返回NULL的方法获得了ArrayList,如果它遇到一些生成ArrayList的错误,如someObject.foo(otherObject.getArrayList());

当然,如果你这样做,你也会遇到问题:

ArrayList list = NULL;
list.size();

现在,在Objective-C中,我们有相同的方法:

- (void)foo:(NSArray*)anArray
{
    int i;
    for(i = 0; i < [anArray count]; ++i){
        NSLog(@"%@", [[anArray objectAtIndex:i] stringValue];
    }
}

现在,如果我们有以下代码:

[someObject foo:nil];

我们有相同的情况,Java会产生NullPointerException.将首先在[anArray count]中访问nil对象.但是,Objective-C将根据上述规则返回0,而不是抛出NullPointerException,因此循环将不会运行.但是,如果我们将循环设置为运行一定次数,那么我们首先在[anArray objectAtIndex:i]向anArray发送一条消息; 这也将返回0,但由于objectAtIndex:返回一个指针,并且指向0的指针为nil/NULL,NSLog将每次通过循环传递nil.(虽然NSLog是一个函数而不是方法,但是如果传递了一个nil NSString,它会打印出来(null).

在某些情况下,有一个NullPointerException更好,因为您可以立即告诉程序有问题,但除非您捕获异常,程序将崩溃.(在C中,尝试以这种方式取消引用NULL会导致程序崩溃.)在Objective-C中,它只会导致可能不正确的运行时行为.但是,如果你有一个方法,如果它返回0/nil/NULL /归零结构不会中断,那么这将使你不必检查以确保对象或参数为零.


值得一提的是,在过去的几十年中,这种行为一直是Objective-C社区争论的主题."安全"和"便利"之间的权衡由不同的人进行不同的评估.
在实践中,将消息传递给nil以及Objective-C如何工作之间存在很多对称性,特别是在ARC中的新弱指针功能中.弱指针会自动归零.因此设计API以便它可以响应0/nil/NIL/NULL等.
@ 11684这是正确的,但` - >`不再是Objective-C操作,而是一个通用的C-ism.

2> Peter Hosey..:

到的消息nil不执行任何操作,并返回nil,Nil,NULL,0,或0.0.



3> Joe McMahon..:

所有其他帖子都是正确的,但也许这就是重要的概念.

在Objective-C方法调用中,任何可以接受选择器的对象引用都是该选择器的有效目标.

这节省了很多"是X型的目标对象吗?" 代码 - 只要接收对象实现选择器,它就完全没有区别!nil是一个NSObject接受任何选择器 - 它只是没有任何事情.这消除了很多"检查零,不发送消息,如果是真的"代码.("如果它接受它,它实现它"概念也允许你创建协议,它有点像Java接口:一个声明,如果一个类实现了声明的方法,那么它符合协议.)

这样做的原因是消除除了让编译器满意之外什么也不做的猴子代码.是的,你得到了另外一个方法调用的开销,但是你节省了程序员时间,这是一个比CPU时间更昂贵的资源.此外,您还可以从应用程序中消除更多代码和更多条件复杂性.

澄清downvoters:你可能认为这不是一个好的方法,但它是语言的实现方式,它是Objective-C中推荐的编程习惯(参见Stanford iPhone编程讲座).



4> Rich..:

这意味着当在nil指针上调用objc_msgSend时,运行时不会产生错误; 相反,它返回一些(通常是有用的)值.可能具有副作用的消息不执行任何操作.

它很有用,因为大多数默认值比错误更合适.例如:

[someNullNSArrayReference count] => 0

即,nil似乎是空阵列.隐藏一个零NSView引用什么都不做.好的,嗯?



5> mmalc..:

在文档的引文中,有两个独立的概念 - 如果文档更清晰,可能会更好:

Cocoa中有几种模式可以利用这一事实.

从消息返回到nil的值也可能是有效的:

前者可能在这里更相关:通常能够发送消息nil使代码更直接 - 您不必在任何地方检查空值.规范示例可能是访问器方法:

- (void)setValue:(MyClass *)newValue {
    if (value != newValue) { 
        [value release];
        value = [newValue retain];
    }
}

如果发送消息nil无效,则此方法会更复杂 - 您必须进行两次额外检查以确保value并且在发送消息之前newValue不会nil.

然而,后一点(从消息返回的值nil通常也是有效的)会给前者增加乘数效应.例如:

if ([myArray count] > 0) {
    // do something...
}

此代码再次不需要检查nil值,并自然流动...

所有这些都表明,能够发送消息的额外灵活性nil确实需要付出一些代价.您可能会在某个阶段编写以特殊方式失败的代码,因为您没有考虑值可能存在的可能性nil.



6> Heath Border..:

来自Greg Parker的网站:

如果运行LLVM Compiler 3.0(Xcode 4.2)或更高版本

Messages to nil with return type | return
Integers up to 64 bits           | 0
Floating-point up to long double | 0.0
Pointers                         | nil
Structs                          | {0}
Any _Complex type                | {0, 0}



7> Kendall Helm..:

这意味着通常不需要为了安全而在任何地方检查零物体 - 特别是:

[someVariable release];

或者,如上所述,当你有一个nil值时,各种count和length方法都返回0,所以你不需要为nil添加额外的nil检查:

if ( [myString length] > 0 )

或这个:

return [myArray count]; // say for number of rows in a table



8> benzado..:

不要想"接收器是零"; 我同意,这很奇怪的.如果您要向nil发送消息,则没有接收方.你只是发送消息给零.

如何处理这是Java和Objective-C之间的哲学差异:在Java中,这是一个错误; 在Objective-C中,它是一个无操作.



9> Nikita Zhuk..:

发送到nil并且其返回值的大小大于sizeof(void*)的ObjC消息在PowerPC处理器上产生未定义的值.除此之外,这些消息还会导致在Intel处理器上大小超过8个字节的结构字段中返回未定义的值.Vincent Gable在他的博文中很好地描述了这一点



10> Rinzwind..:

我认为其他任何答案都没有明确提到这一点:如果你已经习惯了Java,你应该记住,虽然Mac OS X上的Objective-C有异常处理支持,但它是一个可选的语言功能,可以是用编译器标志打开/关闭.我的猜测是,这个设计的"将消息发送到nil安全"早例外,在语言处理支持列入议程,并用一记类似的目标已完成:方法可以返回nil指示错误,因为发送消息nil通常返回nil在转,这允许错误指示传播通过您的代码,因此您不必在每条消息上检查它.您只需要在重要的位置进行检查.我个人认为异常传播和处理是实现这一目标的更好方法,但不是每个人都同意这一点.(另一方面,我不喜欢Java要求你必须声明一个方法可能抛出的异常,这通常会迫使你在整个代码中语法上传播异常声明;但这是另一个讨论.)

我发布了一个类似但更长的回答相关问题"断言在Objective C中每个对象创建都成功了吗?" 如果你想要更多细节.


很好的猜测,但历史上不确定为什么做出决定.从一开始就存在语言中的异常处理,尽管与现代习语相比,原始异常处理程序相当原始.Nil-eats-message是一种有意识的设计选择,源自Smalltalk中Nil对象的*可选*行为.当设计原始的NeXTSTEP API时,方法链接非常普遍,并且"nil"返回用于将链短路到NO-op.
推荐阅读
郑谊099_448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有