原文地址:nil / Nil / NULL / NSNull
理解nothingness
的概念即是一个哲学问题也是一个实用的问题。我们处在一个有逻辑但也充满了不确定性的世界。作为一个逻辑系统的物理体现,计算机要面临一个棘手的问题,用什么来表示nothing。
在Objective-C中,有几种不同的形式来表示nothing。这样做的原因要追溯到NSHispter经常且反复讨论过的议题:Objective-C怎么桥接C语言的语法规则和类SmallTalk的面向对象的语法规则。
C语言用0来表现基本类型变量的nothing,用NULL来表现空指针(这在指针环境中相当于0)。
Objective-C在C的已有的两种表现形式上又加了一个nil来表示nothing。nil是一个不指向任何对象的实例对象指针。尽管在语义上不同于NULL,但他们严格来说是相等的。
在框架层上,Foundation框架定义了一个NSNull类,它定义了一个类方法+null
, 这个方法返回一个NSNull类的单例对象。NSNull 与nil或Null不同,前者是一个真实的对象,而后两者是一个0值。
另外,在Foundation/NSObjCRuntime.h
文件中,Nil被定义为一个不指向任何东西的类对象指针(译者注:区分实例对象指针)。这个由nil的首字母大写的表示形式并不太常见,但它也是用来表示nothing。
关于nil的一些问题
新创建的实例对象在初始化时会把它的内容设置为空。这意味着它所有指针形式的实例变量都会被置为nil,所以,在它的初始化方法中没有必要对这些变量赋值nil。
然而,nil最值得关注的特性应该是它可以接收消息。
在别的编程语言中,如C++,这样做会让你的应用崩溃,但是在Objective-C中,发送给nil的方法会返回一个空值。这很大程度上简化了在需要判断对象是否空再执行方法时的表达形式。
// For example, this expression...
if (name != nil && [name isEqualToString:@"Steve"]) { ... }
// ...can be simplified to:
if ([name isEqualToString:@"Steve"]) { ... }
了解了Objective-C中nil的工作方式,我们可以认识到,nil是Objective-C 的一个方便的语法特性,而不会成为你应用中一个潜伏的bug。记得要注意nil不能出现的地方,可以通过提前返回方法的形式或者使用一个断言来避免这种情况的发生。
NSNull: 用来表示nothing的事物
NSNull 经常在Foundation和其他框架中出现来避免集合类如NSArray和NSDictionary 中不能包含空值的限制。你可以简单的认为 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中四种表示空对象的形式:
Symbol | Value | Meaning |
---|---|---|
NULL | (void *)0 | literal null value for C pointers |
nil | (id)0 | literal null value for Objective-C objects |
Nil | (Class)0 | literal null value for Objective-C classes |
NSNull | [NSNull null] | singleton object used to represent null |