nullable、nonnull、__nullable、__nonnull、_Nullable、__Nonnull 的区别

在苹果自己的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_Nullablenonnull__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 。而且苹果也支持没有下划线的写法 nonnullnullable ,于是就三种写法都可以使用的情况。

从上面的代码可以看出, nullable 修饰于类型前, 但__nullable_Nullable 却修饰于类型后。

那么它们还有其他的区别呢?
对于方法参数、方法返回值、属性的修饰,可以使用:nonnullnullable 或者 _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_BEGINNS_ASSUME_NONNULL_END 。在这两个宏之间的代码,所有简单指针对象都被认为是 nonnull 修饰的 ,所以我们只需要指定 nullable 的指针对象即可。

NS_ASSUME_NONNULL_BEGIN

- (void)methodWithString4:(NSString *)str string:(nullable NSString *)string {}

NS_ASSUME_NONNULL_END

如上写的话, 参数strnonnull的, 而参数stringnullable 的。

总结

对于方法参数、方法返回值、属性的修饰,可以使用:nonnullnullable 或者 _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

猜你喜欢

转载自blog.csdn.net/wangyanchang21/article/details/79230770