Objective-C 中 nullable、__nullable、_Nullable 的區別

在OC中存在__nullable與之對應的__nonnull修飾符,蘋果為了避免與第三方庫潛在的沖突把 __nonnull/__nullable 改成 _Nonnull/_Nullable。同時蘋果同樣還支持沒有下劃線的寫法 nonnull/nullable,這三種寫法本質上都是互通的,只是放的位置不同,意義用途如下:

屬性 表示意義 用途 區別
__nullable 、_Nullable、nullable 表示對象可以是 NULL 或 nil 方法返回值修飾、參數修飾、聲明屬性修飾 放置位置不同
__nonnull、_Nonnull、nonnull 表示對象不應該為空 同上 同上

使用示例:

  • 方法返回值修飾:
- (nullable NSString *)function;
- (NSString * __nullable) function;
- (NSString * _Nullable) function;
  • 聲明屬性的修飾:
@property (nonatomic, copy, nullable) NSString * param;
@property (nonatomic, copy) NSString * __nullable param;
@property (nonatomic, copy) NSString * _Nullable param;
  • 方法參數修飾:
- (void)functionWithParam:(nullable NSString *) param;
- (void)functionWithParam:(NSString * _Nullable) param;
- (void)functionWithParam:(NSString * __nullable) param;

而對于 雙指針類型對象Block 的返回值Block 的參數 等,這時候就不能用 nonnull/nullable 修飾,只能用帶下劃線的 __nonnull/__nullable 或者 _Nonnull/_Nullable

- (void)functionWithError:(NSError * _Nullable * _Nullable)error
- (void)functionWithError:(NSError * __nullable * __null_unspecified)error;
- (void)functionWithBlock:(nullable(整體修飾符位置-外界傳入block是否可以為空) id __nonnull(返回修飾符位置-block返回值是否可以為空)  (^)(id __nullable(參數修飾符位置) params))block;
// 上面的 nullable 用于修飾方法傳入的參數 Block 可以為空,__nonnull 用于修飾 Block 返回值 id 不能為空;

根據原生 iOS SDK 里 Foundation 和 UIKit 的頭文件以及蘋果的博文《Nullability and Objective-C》,總結如下使用規范:

  • 對于屬性、方法返回值、方法參數的修飾,使用:nonnull/nullable
  • 對于 C 函數的參數、Block 的參數、Block 返回值的修飾,使用:_Nonnull/_Nullable建議棄用 __nonnull/__nullable

Nonnull Audited Regions

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

NS_ASSUME_NONNULL_BEGIN
@interface myClass ()
@property (nonatomic, copy) NSString * param;
- (id)functionWithParam:(nullable NSString *)param;
@end
NS_ASSUME_NONNULL_END

在上面的代碼中,param 屬性默認是 nonnull 的,functionWithParam: 方法的返回值也是 nonnull,而方法的參數 str 被顯式指定為 nullable

為了安全起見,蘋果還制定了以下幾條規則:

  • 通過 typedef 定義的類型的 nullability 特性通常依賴于上下文,即使是在 Audited Regions 中,也不能假定它為 nonnull
  • 對于復雜的指針類型(如 id *)必須顯式去指定是 nonnull 還是 nullable。例如,指定一個指向 nullable 對象的 nonnull 指針,可以使用 __nullable id * __nonnull
  • 我們經常使用的 NSError ** 通常是被假定為一個指向 nullable NSError 對象的nullable指針。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。