『Apple API』Nullability

Nullability 最早出现在 Xcode 6.3 中:nullablenonnullnull_unspecifiednull_resettable。意在方便与 Swift 桥接,毕竟 Objective-C 没有 Optional 说法。即使你的 API 不需要支持 Swift,也最好使用这种严谨的写法,来看看 Apple 都提供了哪些东西。

环境信息:
Mac OS X 10.11.6
Xcode 8.0
iOS 10.0

关键字

  • null_unspecified:对应 Swift 的隐式解包可选(缺省值)
  • nullable:可空,对应 Swift 的 ?
  • nonnull:不可空,对应 Swift 的 !
  • null_resettable:set 可空,get 不为空。仅用于 property。

语法

在使用 nonnull 修饰后,如果对值赋空,则会受到编译警告:

Null passed to a callee that requires a non-null argument

除了上面提到的四个关键字外,还可以在很多 API 中看到以下关键字:

  • null_unspecifiednullablenonnull
  • _Nonnull_Nullable_Null_unspecified
  • __nonnull__nullable__null_unspecified

在 Xcode 7 release 版本中,给出的解释如下:

The double-underscored nullability qualifiers (nullable, nonnull, and _null_unspecified) have been renamed to use a single underscore with a capital letter:Nullable, _Nonnull, and _Null_unspecified, respectively). The compiler predefines macros mapping from the old double-unspecified names to the new names for source compatibility.

两个下划线的关键字(__nullable__nonnull__null_unspecified)被重命名为了一个下划线的(_Nullable_Nonnull_Null_unspecified)。编译器使用宏定义来将两个下划线的关键字映射到一个下划线的,以实现兼容。

虽然是新版本做出的语法变更,不过在写法上,还是有一定区别的: 有下划线的关键字(一个两个都是)要写在定义类型后面,而没有下划线的,写在类型前面。

属性

@property (nullable) NSNumber *status;
@property NSNumber * __nullable status;
@property NSNumber * _Nullable status;

函数参数

- (void)doSomethingWithString:(nullable NSString *)str;
- (void)doSomethingWithString:(NSString * _Nullable)str;
- (void)doSomethingWithString:(NSString * __nullable)str;

block

- (void)convertObject:(nullable id __nonnull (^)(nullable id obj))handler;
- (void)convertObject:(id __nonnull (^ _Nullable)())handler;
- (void)convertObject:(id _Nonnull (^ __nullable)())handler;

其实在写 API 的时候,大多数的值需要的都是 nonnull 的,如果每个都进行标记,显得不够优雅,所以 Apple 给出了两个宏:NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END。写在两个 BEGIN 与 END 之间的属性、方法,均会使用 nonnull 修饰。

NS_ASSUME_NONNULL_BEGIN

@interface NSDate : NSObject <NSCopying, NSSecureCoding>

@property (readonly) NSTimeInterval timeIntervalSinceReferenceDate;

- (instancetype)init NS_DESIGNATED_INITIALIZER;
// 如果在其中有变量需要用 nullable 修饰,直接加就好
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

@end

NS_ASSUME_NONNULL_END

《『Apple API』Nullability》有3个想法

发表评论

电子邮件地址不会被公开。