nil / Nil / NULL / NSNull 之间不可不说的细节

此文章为对英文原文的翻译,如有错误,欢迎指正~戳这里进英文原文.

理解“虚无”这个概念不仅是个哲学问题,同样也是一个很现实的问题。我们存在于物质的世界中,但是……。 作为逻辑系统的物理展示,计算机面临一个很棘手的问题——如何 “有” 表示 “ 无”。

在Objective-C中,“无”的表示有多种。关于Objective-C如何桥接C的过程式范式和类似Smalltalk语言的面向对象式范式,可以回到这篇文章:a common NSHipster refrain

对于原始值,C使用数字“0”来表示“无”,而对于指针则是使用NULL来表示。(关于“0”和NULL的使用可参考这篇文章)

Objective-C在C的基础上新增了一种表示“无”的方式——nil。nil是一个指向空对象的指针。虽然在字义上与NULL不同,但其实他们是一样的——都是指向空的指针。

从框架层面上讲,Foundation框架定义了NSNull,而且它有且仅有一个类方法——+null,而这个方法返回一个NSNull的单例。NSNull与nil或者NULL都不相同,因为它是一个具体的对象,而不是一个空值。

另外,在Foundation/NSObjCRuntime.h头文件中,Nil被定义为一个指向空的类对象的指针。虽然Nil相对于nil不那么常见,但是我们也有必要知道它。

关于nil

新alloc出来的NSObject的对象被初始化为0。这意味着所有的对象指针被创建出来就指向了nil,所以不需要在init方法中将新创建的对象设置为nil,如
self.(association) = nil

对于nil,可能最常见的行为是能给它发送消息。。

在其他的语言里面,比如C++,这个会使你的程序崩溃,但是在Objective-C中,nil去调用方法仅仅只是返回一个空值。这就不用在做一些事情之前做是否为nil的判断来防止程序崩溃了,例如:

// For example, this expression...
if (name != nil && [name isEqualToString:@"Steve"]) { ... }

// ...can be simplified to:
if ([name isEqualToString:@"Steve"]) { ... }

在Objective-C中,知道nil的工作机制可以使这种便利成为一个特色,而不会成为你应用之中一个潜藏的bug。不过在一些不想要nil出现的场合,一定要防止nil的出现,比如提前检查及返回失败,或者使用NSParameterAssert来抛出异常。

NSNull:“空”的实例

NSNull是用于在Foundation和其他的一些框架中为了绕开容器类,如:NSArray 和 NSDictionary 中不能包含nil值的问题。你可以把NSNull看做一个可以把NULL或nil装起来的“容器”,以使用于容器类中:

NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
mutableDictionary[@"someKey"] = [NSNull null]; // Sets value of NSNull singleton for `someKey`
NSLog(@"Keys: %@", [mutableDictionary allKeys]); // @[@"someKey"]

结语

回顾一下,所有使用Objective-C编程的程序员都应该了解这4种表示“无”的方式:

Symbol Value Meaning
NULL (void *)0 C指针的空值
nil (id)0 OC对象的空值
Nil (Class)0 OC类对象的空值
NSNull [NSNull null] 用于表示空值的单例

你可能感兴趣的:(nil / Nil / NULL / NSNull 之间不可不说的细节)