在C語言中用0來作為"不存在"的原始值,而用NULL作為指針空值。在Objective-C中,則有幾種不同的方式來表示"不存在",分別有:NULL、nil、Nil、NSNull。下面我們來看看這幾種空值的定義以及使用上的不同。
注: 以下各種空值定義的源碼摘自iOS 10.0 SDK中的相關(guān)頭文件
NULL
NULL定義在user/include/sys/_types/_null.h文件里:
#ifndef NULL
#define NULL _ _DARWIN_NULL
#endif /* NULL */
其中 _ _DARWIN_NULL 的定義在usr/include/sys/_ _types.h文件里,如下:
#ifdef __cplusplus
# ifdef __GNUG__
# define __DARWIN_NULL __null
# else /* ! __GNUG__ */
# ifdef __LP64__
# define __DARWIN_NULL (0L)
# else /* !__LP64__ */
# define __DARWIN_NULL 0
# endif /* __LP64__ */
# endif /* __GNUG__ */
#else /* ! __cplusplus */
# define __DARWIN_NULL ((void *)0)
#endif /* __cplusplus */
上述代碼首先定義在C++環(huán)境下不同編譯器的_ _DARWIN_NULL的取值,然后定了其他環(huán)境下_ _DARWIN_NULL的值,因此在Objective-C中NULL的最終定義為:
#define NULL ((void*)0)
即NULL本質(zhì)上是:(void*)0。
使用慣例:NULL一般用于表示C指針空值,例如:
int *pointerToInt = NULL;
char *pointerToChar = NULL;
struct TreeNode *rootNode = NULL;
nil
nil定義在usr/include/objc/objc.h文件里:
#ifndef nil
# if __has_feature(cxx_nullptr)
# define nil nullptr
# else
# define nil __DARWIN_NULL
# endif
#endif
其中_ _has_feature(cxx_nullptr)用于判斷當(dāng)前環(huán)境是否有C++的nullptr特性,如果有.nil定義為nullptr,否則nil定義為**_ _DARWIN_NULL,所以在Objective-C中nil的最終定義為:
#define nil ((void*)0)
也就是說,nil本質(zhì)上也是:(void *)0,與NULL一致。
使用慣例:nil用于表示指向Objective-C對(duì)象(id類型的對(duì)象,或者使用@interface聲明的OC對(duì)象)的指針為空,例如:
NSString *someString = nil;
NSURL *someURL = nil;
id someObject = nil;
if (anotherObject == nil) // do something
Nil
Nil定義在usr/include/objc/objc.h文件里:
#ifndef Nil
# if __has_feature(cxx_nullptr)
# define Nil nullptr
# else
# define Nil __DARWIN_NULL
# endif
#endif
與上述nil一致,Nil本質(zhì)上也是:(void *)0。
使用慣例:Nil用于表示指向Objective-C類(Class)類型的指針為空,例如:
Class someClass = Nil;
Class anotherClass = [NSString class];
NSNull
NSNull定義在NSNull.h文件里:
#import
NS_ASSUME_NONNULL_BEGIN
@interface NSNull : NSObject
+ (NSNull *)null;
@end
NS_ASSUME_NONNULL_END
從上述定義中,我們可知NSNull是一個(gè)Objective-C對(duì)象,是一個(gè)用于表示空值得類,而且它只有一個(gè)單例方法:+[NSNull null],一般用于在集合對(duì)象中保存一個(gè)空的占位對(duì)象。
使用慣例:在Foundation集合對(duì)象(NSArray、NSDictionary、NSSet等)中,nil通常被用于表示集合對(duì)象結(jié)束的標(biāo)志,因此無法用nil來存儲(chǔ)一個(gè)空值,所以一般用[NSNull null]空對(duì)象來存儲(chǔ)。另外,在NSDictionary的-objectForKey:方法中,如果當(dāng)前字典中key對(duì)應(yīng)的值不存在,該方法會(huì)返回nil,表明當(dāng)前key在字典中未添加,但是如果我們想明確表示某一key已經(jīng)在字典中添加,但是它沒有值,這時(shí)候就可以用[NSNull null]來賦值表示。
// 當(dāng) NSArray 里遇到 nil 時(shí),就說明這個(gè)數(shù)組對(duì)象的元素截止了,即 NSArray 只關(guān)注 nil 之前的對(duì)象,nil 之后的對(duì)象會(huì)被拋棄。
NSArray *array = [NSArray arrayWithObjects:@"one", @"two", nil];
// 錯(cuò)誤的使用
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:nil forKey:@"someKey"];
// 正確的使用
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:[NSNull null] forKey:@"someKey"];
NIL或NSNil
Objective-C中不存在這兩個(gè)符號(hào)!!!
總結(jié)
從上述分析我們可知,不管是NULL、nil還是Nil,它們本質(zhì)上是一樣的,都是(void )0,只是寫法不同。這樣做的意義是為了區(qū)分不同的數(shù)據(jù)類型,雖然它們值相同,但我們需要理解它們之間的字面意義并用于不同場景,讓代碼更加準(zhǔn)確,增加可讀性。
標(biāo)志 值 含義
NULL (void)0 C指針的字面空值
nil (id)0 Objective-C 對(duì)象的字面空值
Nil (Class)0 Objective-C 類的字面空值
NSNull [NSNull null] 用來表示空值的Objective-C對(duì)象