nullable、__nullable、_Nullable 區(qū)別

蘋果在 Xcode 6.3 引入了一個(gè) Objective-C 的新特性:Nullability Annotations,這一新特性的核心是兩個(gè)新的類型修飾:__nullable和__nonnull。從字面上我們可知,__nullable表示對(duì)象可以是 NULL 或 nil,而__nonnull表示對(duì)象不應(yīng)該為空。當(dāng)我們不遵循這一規(guī)則時(shí),編譯器就會(huì)給出警告。在 Xcode 7 中,為了避免與第三方庫(kù)潛在的沖突,蘋果把__nonnull/__nullable改成_Nonnull/_Nullable。再加上蘋果同樣支持了沒(méi)有下劃線的寫法nonnull/nullable,于是就造成現(xiàn)在有三種寫法這樣混亂的局面。但是這三種寫法本質(zhì)上都是互通的,只是放的位置不同,舉例如下:

方法返回值修飾:

- (nullableNSString*)method;- (NSString* __nullable)method;- (NSString* _Nullable)method;

聲明屬性的修飾:

@property(nonatomic,copy,nullable)NSString*aString;

@property(nonatomic,copy)NSString* __nullableaString;

@property(nonatomic,copy)NSString* _Nullable aString;

方法參數(shù)修飾:

- (void)methodWithString:(nullableNSString*)aString;- (void)methodWithString:(NSString* _Nullable)aString;- (void)methodWithString:(NSString* __nullable)aString;

而對(duì)于雙指針類型對(duì)象、Block 的返回值、Block 的參數(shù)等,這時(shí)候就不能用nonnull/nullable修飾,只能用帶下劃線的__nonnull/__nullable或者_(dá)Nonnull/_Nullable:

- (void)methodWithError:(NSError* _Nullable * _Nullable)error- (void)methodWithError:(NSError* __nullable* __null_unspecified)error;// 以及其他的組合方式

- (void)methodWithBlock:(nullablevoid(^)())block;// 注意上面的 nullable 用于修飾方法傳入的參數(shù) Block 可以為空,而不是修飾 Block 返回值;- (void)methodWithBlock:(void(^ _Nullable)())block;- (void)methodWithBlock:(void(^ __nullable)())block;

- (void)methodWithBlock:(nullableid__nonnull(^)(id__nullableparams))block;

// 注意上面的 nullable 用于修飾方法傳入的參數(shù) Block可以為空,而 __nonnull 用于修飾 Block 返回值 id 不能為空;

- (void)methodWithBlock:(id__nonnull(^ __nullable)(id__nullableparams))block;

- (void)methodWithBlock:(id_Nonnull (^ _Nullable)(id_Nullable params))block;

// the method accepts a nullable blockthat returns a nonnullvalue

// therearesomemore combinations here, yougetthe idea

以上基本上羅列了絕大部分的使用場(chǎng)景,但看完我們還是一臉懵逼啊,仍然不清楚什么時(shí)候應(yīng)該用哪個(gè)修飾符!

在看了原生 iOS SDK 里 Foundation 和 UIKit 的頭文件以及蘋果的博文《Nullability and Objective-C》,我們總結(jié)如下使用規(guī)范:

對(duì)于屬性、方法返回值、方法參數(shù)的修飾,使用:nonnull/nullable;

對(duì)于 C 函數(shù)的參數(shù)、Block 的參數(shù)、Block 返回值的修飾,使用:_Nonnull/_Nullable,建議棄用__nonnull/__nullable。

Nonnull Audited Regions

如果需要每個(gè)屬性或每個(gè)方法都去指定nonnull和nullable,將是一件非常繁瑣的事。蘋果為了減輕我們的工作量,專門提供了兩個(gè)宏:NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END。在這兩個(gè)宏之間的代碼,所有簡(jiǎn)單指針對(duì)象都被假定為nonnull,因此我們只需要去指定那些nullable指針對(duì)象即可。如下代碼所示:

NS_ASSUME_NONNULL_BEGIN

@interfacemyClass()

@property(nonatomic,copy)NSString*aString;

-(id)methodWithString:(nullableNSString*)str;

@end

NS_ASSUME_NONNULL_END

在上面的代碼中,aString屬性默認(rèn)是nonnull的,methodWithString:方法的返回值也是nonnull,而方法的參數(shù)str被顯式指定為nullable。

不過(guò),為了安全起見(jiàn),蘋果還制定了以下幾條規(guī)則:

通過(guò)typedef定義的類型的nullability特性通常依賴于上下文,即使是在 Audited Regions 中,也不能假定它為nonnull;

對(duì)于復(fù)雜的指針類型(如id *)必須顯式去指定是nonnull還是nullable。例如,指定一個(gè)指向nullable對(duì)象的nonnull指針,可以使用__nullable id * __nonnull;

我們經(jīng)常使用的NSError **通常是被假定為一個(gè)指向nullableNSError 對(duì)象的nullable指針。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容