Objective-C 中的 Nullability
自从 Swift 发布,就有一个很重要的特性:Optional,提供了更严格的类型检查,使得在编译时就能发现更多空变量问题。同时我们知道的是 Swift 可以与 Objective-C 混合编译,那么 Swift 中的 Optional 特性如何与 Objective-C 兼容呢?同时 Nullability 给 Objective-C 带来哪些改进?
0x00 全新的修饰符
苹果在 Xcode 6.3 中引入了 Nullability 特性,这一新特性的核心就是两个新的修饰符:__nullable
和 __nonnull
,顾名思义前者为可空修饰,后者为不可空修饰,在编译时编译器会对此规则进行检查,并对未遵守规则的代码给出警告(在 Swift 中是无法通过编译的)。
但是为什么又有 _Nullable
和 _Nonnull
呢?这两个新的写法是在 Xcode 7 中新增的,苹果给出的理由是:Due to potential conflicts with third-party libraries,为了避免与第三方库潜在的冲突。
但是又特么的为什么有 nullable
和 nonnull
呢?根据苹果的说法,其实就是为了方便书写新增的。
综上所述,__nullable
和 _Nullable
和 nullable
作用是一样的,同理 __nonnull
和 _Nonnull
和 nonnull
的作用也是一样的,但 __nullable
和 __nonnull
算是不推荐使用了,输入也麻烦,所以接下来的例子就不讨论这两个了。
0x01 该怎么用
属性声明修饰
@property (nonatomic, copy, nullable) NSString *name;
@property (nonatomic, copy) NSString * _Nullable name;
方法返回值修饰
- (nullable NSString *)method;
- (NSString * _Nullable)method;
方法参数修饰
- (void)methodWithString:(nullable NSString *)string;
- (void)methodWithString:(NSString * _Nullable)string;
- (void)methodWithBlock:(nullable void (^)())block;
- (void)methodWithBlock:(nonnull void (^)())block;
虽然说 nullable
和 nonnull
看起来最顺眼,但不是所有场景都能使用的,因此举一堆例子🌰:
双指针类型对象修饰
- (void)methodWithError:(NSError * _Nullable * _Nullable)error;
Block 返回值修饰
- (void)methodWithBlock:(NSString * _Nullable(^)())block;
- (void)methodWithBlock:(NSString * _Nonnull(^)())block;
组合情况修饰
- (void)methodWithBlock:(nullable NSString * _Nullable(^)(NSError * _Nullable * _Nullable error))block;
哈!是不是有点烧脑了~
0x02 Audited Regions
如果一个文件中大量 property 或者方法都要设置 nonnull
,那么我们就要重复多次添加对应的修饰符,那就很麻烦了,因此 Xcode 给我们提供了 Audited Regions Annotation 来简化这些操作。
在需要标记的区域头尾分别添加 NS_ASSUME_NONNULL_BEGIN
和 NS_ASSUME_NONNULL_END
就可以了:
NS_ASSUME_NONNULL_BEGIN
@interface UUObject ()
@property (nonatomic, copy) NSString *lastName; // 默认为 nonnull
@property (nonatomic, copy, nullable) NSString *firstName; // 指定为 nullable
- (void)methodAWithString:(NSString *)string; // 默认为 nonnull
- (void)methodBWithString:(nullable NSString *)string; // 指定为 nullable
@end
NS_ASSUME_NONNULL_END
0x03 总结
使用 nonnull
和 nullable
:
- 属性
- 方法返回值
- 方法参数
使用 _Nonnull
和 _Nullable
:
- C 函数相关参数
- Block 参数
- Block 返回值
__nonnull
和 __nullable
?不存在的。