nullable、__nullable、_Nullable 探究
解决的问题
Swift中可以用optional还是non-optional区分一个参数是否为空,但是OC是一种非常古老的语言,并没有这一功能。那么,当Swfit与OC混编的时候就尴尬了。Swift编译器不知道OC参数是optional还是non-optional,这时编译器回把OC参数统统当作non-optional来处理。这中方法就优势妥当。
解决方案
在Xcode6.3中Apple引入OC新特性Nullability Annotations,这一新特性核心是两个类型修饰符--nonnull(表示对象可以是NULL或者nul)和 --nonnull(表示不能为空)。
在Xcode7中,为解决与第三方库潜在的冲突,Apple又将--nonnull/--nullable改成 _Nonnull/_Nullable,但是__nonnull/__nullable也没有被Apple舍弃。Apple建议使用_Nonnull/_Nullable。
存在以上两种形式的写法情况下,苹果同样支持不带下划线的写法nonnull/nullable
到此为止,三种写法共存的局面出现了...
如果需要每个属性或每个方法都去指定nonnull和nullable,是一件非常繁琐的事。苹果为了减轻我们的工作量,专门提供了两个宏:NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END。
用法
建议使用过程中放弃--nonnull/--nullable的写法
- 申明方法时 带下划线修饰符放在参数类型的后面,不带下划线的修饰符写在参数类型前面
- (nullable NSString *)methodWithString:(nullableNSString*)aString;
- (NSString * _Nullable)methodWithString:(NSString* _Nullable)aString;
- 申明属性时
@property(nonatomic,copy,nullable) NSString *aString;
@property(nonatomic,copy)NSString * __Nullable aString;
- 申明block时
- (void)methodWithBlock:(id _Nonnull (^ _Nullable)(id _Nullable params))block;
注意事项
对于 双指针类型对象 、 Block 的返回值 、 Block 的参数 等,这时候就不能用 nonnull/nullable 修饰,只能用带下划线的 __nonnull/__nullable 或者 _Nonnull/_Nullable
- (void)methodWithError:(NSError * _Nullable * _Nullable)error
总结
- 对于属性、方法返回值、方法参数的修饰,使用: nonnull/nullable ;(放在参数类型前面)
- 对于 C 函数的参数、Block 的参数、Block 返回值的修饰,使用: _Nonnull/_Nullable , 建议弃用 __nonnull/__nullable 。(放在参数类型后面)