当前位置: 首页>编程日记>正文

Objective-C中nullable、__nullable、_Nullable、_Nonnull的用法

Objective-C中nullable、__nullable、_Nullable、_Nonnull的用法

在?Swift?中,我们会使用???和?!?去显式声明一个对象或者方法的参数是optional?还是?non-optional?,而在?Objective-C?中则没有这一区分,这样就会带来一个问题:在?Swift?与Objective-C?混编时,Swift?编译器并不知道一个?Objective-C?对象或者一个方法的参数到底是?optional?还是?non-optional?,因此这种情况下编译器会隐式地都当成是?non-optional?来处理,这显然是不太好的。

挖坑

为了解决这个问题,苹果在?Xcode 6.3?引入了一个?Objective-C?的新特性:?Nullability Annotations?,这一新特性的核心是两个新的类型修饰:?__nullable?和?__nonnull?。从字面上我们可知,?__nullable?表示对象可以是?NULL?或?nil,而__nonnull?表示对象不应该为空。当我们不遵循这一规则时,编译器就会给出警告。在?Xcode 7?中,为了避免与第三方库潜在的冲突,苹果把?__nonnull/__nullable改成?_Nonnull/_Nullable?。再加上苹果同样支持了没有下划线的写法?nonnull/nullable?,于是就造成现在有三种写法这样混乱的局面。但是这三种写法本质上都是互通的,只是放的位置不同,举例如下:

Objective-C中nullable、__nullable、_Nullable、_Nonnull的用法,第1张

? ??而对于双指针类型对象?、?Block 的返回值?、?Block 的参数?等,这时候就不能用?nonnull/nullable?修饰,只能用带下划线的?__nonnull/__nullable?或者?_Nonnull/_Nullable?:

Objective-C中nullable、__nullable、_Nullable、_Nonnull的用法,第2张

以上基本上罗列了绝大部分的使用场景,但看完我们还是一脸懵逼啊,仍然不清楚什么时候应该用哪个修饰符!

总结如下:

在看了原生 iOS SDK 里 Foundation 和 UIKit 的头文件以及苹果的博文?《Nullability and Objective-C》?,我们总结如下使用规范:

对于属性、方法返回值、方法参数的修饰,使用:nonnull/nullable;

对于 C 函数的参数、Block 的参数、Block 返回值的修饰,使用:_Nonnull/_Nullable,建议弃用__nonnull/__nullable

Nonnull Audited Regions

如果需要每个属性或每个方法都去指定?nonnull?和?nullable?,将是一件非常繁琐的事。苹果为了减轻我们的工作量,专门提供了两个宏:?NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END。在这两个宏之间的代码,所有简单指针对象都被假定为nonnull,因此我们只需要去指定那些nullable指针对象即可。如下代码所示:

Objective-C中nullable、__nullable、_Nullable、_Nonnull的用法,第3张

在上面的代码中,aString属性默认是nonnull的,methodWithString:方法的返回值也是nonnull,而方法的参数str被显式指定为nullable。

不过,为了安全起见,苹果还制定了以下几条规则:

Objective-C中nullable、__nullable、_Nullable、_Nonnull的用法,第4张

通过typedef定义的类型的nullability特性通常依赖于上下文,即使是在 Audited Regions 中,也不能假定它为nonnull;

对于复杂的指针类型(如id *)必须显式去指定是nonnull还是nullable。例如,指定一个指向nullable对象的nonnull指针,可以使用__nullable id * __nonnull;

我们经常使用的NSError **通常是被假定为一个指向nullableNSError 对象的nullable指针。

转自:http://www.tuicool.com/articles/ZBnEveU


相关文章: