nil&Nil&NULL
- (void)nil_Nil_NULL
{
NSLog(@"nil = %p, Nil = %p, Null = %p", nil, Nil, NULL);
NSLog(@"equal(nil, Nil) = %d, equal(nil, NULL) = %d, equal(Nil, NULL) = %d", nil == Nil, nil == NULL, Nil == NULL);
int *pi;
pi = nil;
pi = Nil;
pi = NULL;
NSObject *obj;
obj = nil;
obj = Nil;
obj = NULL;
Class cls;
cls = nil;
cls = Nil;
cls = NULL;
}
output:
nil = 0x0, Nil = 0x0, Null = 0x0
equal(nil, Nil) = 1, equal(nil, NULL) = 1, equal(Nil, NULL) = 1
总结:
- nil,Nil,NULL都是指针类型常量0,表示指针为空,不指向任何对象,可交互使用,语法上无问题
- nil,Nil,NULL语义上不同,可理解为nil为(id)0,Nil为(Class)0,NULL为(void *)0
- 为增强代码可读性,instance object指针使用nil,class object指针使用Nil,c类型指针使用NULL
空对象
@interface FBAnimal : NSObject
{
@public
int _food;
}
@end
@implementation FBAnimal
- (void)info
{
NSLog(@"food = %d", _food);
}
@end
- (void)empty_obj
{
NSLog(@"instance object not nil");
FBAnimal *animal1 = [[FBAnimal alloc] init];
animal1->_food = 5;
[animal1 info];
NSLog(@"instance object nil");
FBAnimal *animal2 = nil;
//animal2->_food = 8;
[animal2 info];
NSLog(@"class object not Nil");
Class cls1 = [FBAnimal class];
FBAnimal *animal3 = [[cls1 alloc] init];
animal3->_food = 15;
[animal3 info];
NSLog(@"class object Nil");
Class cls2 = Nil;
FBAnimal *animal4 = [[cls2 alloc] init];
//animal4->_food = 18;
[animal4 info];
}
output:
instance object not nil
food = 5
instance object nil
class object not Nil
food = 15
class object Nil
总结:
- 调用方法成员本质是转换为objc_msgSend系列函数,而objc_msgSend系列函数内置了空对象判断机制,因此空对象调用方法成员不会crash,因此可omit对象为空判断,节省代码,提高执行效率
- 访问数据成员本质是通过offset直接访问内存空间,没有任何判断对象为空机制,因此空对象访问数据成员必然crash
注:c++中实例对象不管是调用方法成员或访问数据成员都没有任何判断对象为空机制,因此空对象不管调用方法成员或访问数据成员都必然crash
NSNull
NSNull是类,单例实现,空对象(非nil或Nil),常用在容器中表示容器元素为空,容器元素不允许空对象(nil或Nil),空对象(nil或Nil)在容器中作为容器结束标记符,起哨兵作用
- (void)use_NSNull
{
NSString *animal = nil;
NSArray *animals1 = [NSArray arrayWithObjects:@"dog", [NSNull null], @"cat", nil];
NSArray *animals2 = [NSArray arrayWithObjects:@"dog", nil, @"cat", animal, nil];
NSArray *animals3 = [NSArray arrayWithObjects:@"dog", animal, @"cat", nil];
NSLog(@"animals1 count = %ld", animals1.count);
NSLog(@"animals2 count = %ld", animals2.count);
NSLog(@"animals3 count = %ld", animals3.count);
}
output:
animals1 count = 3
animals2 count = 1
animals3 count = 1
注:容器添加元素时,运行时判断,一旦遇到空对象(nil或Nil),容器添加元素结束,ignore之后元素