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

2024-04-30 07:08

本文主要是介绍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 ,于是就造成现在有三种写法这样混乱的局面。但是这三种写法本质上都是互通的,只是放的位置不同,举例如下:

方法返回值修饰

- (nullableNSString*)method;
- (NSString* __nullable)method;
- (NSString* _Nullable)method;


    声明属性的修饰:
@property (nonatomic,copy,nullable) NSString *aString;
@property (nonatomic,copy) NSString* __nullable aString;
@property (nonatomic,copy) NSString* _Nullable aString;

    方法参数修饰:

- (void)methodWithString:(nullable NSString*)aString;
- (void)methodWithString:(NSString* _Nullable)aString;
- (void)methodWithString:(NSString* __nullable)aString;

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

- (void)methodWithError:(NSError* _Nullable * _Nullable)error
- (void)methodWithError:(NSError* __nullable* __null_unspecified)error;
// 以及其他的组合方式- (void)methodWithBlock:(nullablevoid(^)())block;
// 注意上面的 nullable 用于修饰方法传入的参数 Block 可以为空,而不是修饰 Block 返回值;
- (void)methodWithBlock:(void(^ _Nullable)())block;
- (void)methodWithBlock:(void(^ __nullable)())block;- (void)methodWithBlock:(nullableid__nonnull(^)(id__nullableparams))block;
// 注意上面的 nullable 用于修饰方法传入的参数 Block 可以为空,而 __nonnull 用于修饰 Block 返回值 id 不能为空;
- (void)methodWithBlock:(id__nonnull(^ __nullable)(id__nullableparams))block;
- (void)methodWithBlock:(id_Nonnull (^ _Nullable)(id_Nullable params))block;
// the method accepts a nullable block that returns a nonnull value
// there are some more combinations here, you get the idea

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

总结如下:

在看了原生 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 指针对象即可。如下代码所示:

NS_ASSUME_NONNULL_BEGIN@interfacemyClass()@property (nonatomic,copy) NSString *aString;- (id)methodWithString:(nullable NSString*)str;@endNS_ASSUME_NONNULL_END

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

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

  • 通过 typedef 定义的类型的 nullability 特性通常依赖于上下文,即使是在 Audited Regions 中,也不能假定它为 nonnull ;
  • 对于复杂的指针类型(如 id * )必须显式去指定是 nonnull 还是 nullable 。例如,指定一个指向 nullable 对象的 nonnull 指针,可以使用 __nullable id * __nonnull ;
  • 我们经常使用的 NSError ** 通常是被假定为一个指向 nullable NSError 对象的 nullable 指针。

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

这篇关于Objective-C中nullable、__nullable、_Nullable、_Nonnull的用法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/948195

相关文章

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

解读GC日志中的各项指标用法

《解读GC日志中的各项指标用法》:本文主要介绍GC日志中的各项指标用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基础 GC 日志格式(以 G1 为例)1. Minor GC 日志2. Full GC 日志二、关键指标解析1. GC 类型与触发原因2. 堆

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

JavaSE正则表达式用法总结大全

《JavaSE正则表达式用法总结大全》正则表达式就是由一些特定的字符组成,代表的是一个规则,:本文主要介绍JavaSE正则表达式用法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录常用的正则表达式匹配符正则表China编程达式常用的类Pattern类Matcher类PatternSynta

MySQL之InnoDB存储引擎中的索引用法及说明

《MySQL之InnoDB存储引擎中的索引用法及说明》:本文主要介绍MySQL之InnoDB存储引擎中的索引用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录1、背景2、准备3、正篇【1】存储用户记录的数据页【2】存储目录项记录的数据页【3】聚簇索引【4】二

mysql中的数据目录用法及说明

《mysql中的数据目录用法及说明》:本文主要介绍mysql中的数据目录用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、版本3、数据目录4、总结1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的

深度解析Python装饰器常见用法与进阶技巧

《深度解析Python装饰器常见用法与进阶技巧》Python装饰器(Decorator)是提升代码可读性与复用性的强大工具,本文将深入解析Python装饰器的原理,常见用法,进阶技巧与最佳实践,希望可... 目录装饰器的基本原理函数装饰器的常见用法带参数的装饰器类装饰器与方法装饰器装饰器的嵌套与组合进阶技巧

Mysql中isnull,ifnull,nullif的用法及语义详解

《Mysql中isnull,ifnull,nullif的用法及语义详解》MySQL中ISNULL判断表达式是否为NULL,IFNULL替换NULL值为指定值,NULLIF在表达式相等时返回NULL,用... 目录mysql中isnull,ifnull,nullif的用法1. ISNULL(expr) → 判

Java中的for循环高级用法

《Java中的for循环高级用法》本文系统解析Java中传统、增强型for循环、StreamAPI及并行流的实现原理与性能差异,并通过大量代码示例展示实际开发中的最佳实践,感兴趣的朋友一起看看吧... 目录前言一、基础篇:传统for循环1.1 标准语法结构1.2 典型应用场景二、进阶篇:增强型for循环2.

Python get()函数用法案例详解

《Pythonget()函数用法案例详解》在Python中,get()是字典(dict)类型的内置方法,用于安全地获取字典中指定键对应的值,它的核心作用是避免因访问不存在的键而引发KeyError错... 目录简介基本语法一、用法二、案例:安全访问未知键三、案例:配置参数默认值简介python是一种高级编