在苹果自己的API中, 我们也见过许多的参数的修饰符, 比如说在方法中修饰参数可否为空的标识。今天来总结下 nullable
, nonnull
, __nullable
, __nonnull
, _Nullable
, __Nonnull
之间的区别。
作用
首先, nonnull
, __nonnull
, __Nonnull
这三个修饰的参数是不可以为nil
的。如果参数被它们修饰, 且传入的实参为nil
的话, 编译器将会产生警告。
nullable
, __nullable
, _Nullable
这三个修饰的参数是可以为nil
的。如果参数被它们修饰, 且传入的实参为nil
的话, 编译器也不会产生警告。
用法
// string 可以为 nil
- (void)methodWithString:(nullable NSString *)string {}
// string 不可以为 nil
- (void)methodWithString:(nonnull NSString *)string {}
nullable
、__nullable
、_Nullable
的区别联系
nullable
、__nullable
、_Nullable
和 nonnull
、__nonnull
、__Nonnull
其实是成对的, 所以这里只介绍前者, 后者用法与前者一致。
先来看一段代码, 可以考虑下它们之间的区别是什么。
@property (nonatomic, copy, nullable) NSString *string1;
@property (nonatomic, copy) NSString * _Nullable string2;
@property (nonatomic, copy) NSString * __nullable string3;
- (void)methodWithString1:(nullable NSString *)string {}
- (void)methodWithString2:(NSString * _Nullable)string {}
- (void)methodWithString3:(NSString * __nullable)string {}
其实呢, 这三种写法的效果都是一样的,只是代码摆放的位置不同。
苹果在 Xcode 6.3
引入了一个 Objective-C
的新特性: Nullability Annotations
,它的核心是两个修饰: __nullable
和 __nonnull
。在 Xcode 7
中,为了避免与第三方库潜在的冲突,苹果把 __nonnull
、__nullable
改成 _Nonnull
、_Nullable
。而且苹果也支持没有下划线的写法 nonnull
、nullable
,于是就三种写法都可以使用的情况。
从上面的代码可以看出, nullable
修饰于类型前, 但__nullable
和 _Nullable
却修饰于类型后。
那么它们还有其他的区别呢?
对于方法参数、方法返回值、属性的修饰,可以使用:nonnull
、nullable
或者 _Nonnull
、_Nullable
或者 __nonnull
、__nullable
。
对于 C函数的参数、Block的参数、Block返回值的修饰,只能使用: _Nonnull
、_Nullable
或者 __nonnull
、__nullable
。但是根据苹果的API来说建议弃用__nonnull
、__nullable
。
所以应该按照下面的代码来写:
// C函数
- (void)methodWithError1:(NSError * _Nullable * _Nullable)error {}
// Block 返回值
- (void)methodWithBlock1:(void(^ _Nullable)(void))block {}
- (void)methodWithBlock2:(void(^ __nullable)(void))block {}
// 注意下面的 nullable 用于修饰传入的参数 block 可以为空,而不是修饰 block 返回值
- (void)methodWithBlock3:(nullable void(^)(void))block {}
// Block返回值 和 Block参数
- (void)methodWithBlock4:(NSString * __nonnull(^ __nullable)(NSString * __nullable params))block {}
- (void)methodWithBlock5:(NSString * _Nonnull (^ _Nullable)(NSString * _Nullable params))block {}
// 注意下面的 nullable 用于修饰方法传入的参数 block 可以为空,而 __nonnull 用于修饰 block 返回值 NSString 不能为空;
- (void)methodWithBlock6:(nullable NSString * __nonnull(^)(NSString * __nullable params))block {}
拓展 Nonnull Audited Regions
有两个宏 NS_ASSUME_NONNULL_BEGIN
和 NS_ASSUME_NONNULL_END
。在这两个宏之间的代码,所有简单指针对象都被认为是 nonnull
修饰的 ,所以我们只需要指定 nullable
的指针对象即可。
NS_ASSUME_NONNULL_BEGIN
- (void)methodWithString4:(NSString *)str string:(nullable NSString *)string {}
NS_ASSUME_NONNULL_END
如上写的话, 参数str
为 nonnull
的, 而参数string
为 nullable
的。
总结
对于方法参数、方法返回值、属性的修饰,可以使用:nonnull
、nullable
或者 _Nonnull
、_Nullable
或者 __nonnull
、__nullable
。
对于 C函数的参数、Block的参数、Block返回值的修饰,只能使用: _Nonnull
、_Nullable
或者 __nonnull
、__nullable
。但是根据苹果的API来说建议弃用__nonnull
、__nullable
。
Demo下载地址:
Demo
参考资料:
Difference between nullable, __nullable and _Nullable in Objective-C