转自:https://zhuanlan.zhihu.com/p/25876528
Objective-C 中 空指针校验
Objective-C 是 C 的超集,在日常编程中,会使用一些 C 语言代码。 需要对 C 语言和 Objective-C分别讨论。
1.1 C 语言的空指针校验
在传入某个函数内,检查某个指针是否为空。通常使用断言assert。
这里要介绍一个 xcode 静态分析器上的功能。
可以将 C 语言空指针调用找出来。
![](https://img.haomeiwen.com/i6869774/8278f23ca627cb4c.png)
这里的nonnull表示,不能为空。1,3表示,第一个参数和第三个参数是不能为空指针的。如果传入空指针,编译通过,运行时报错。使用静态分析器会提示你,这里使用了空指针。
在NullPointerCheck.m 上两个函数的定义:
![](https://img.haomeiwen.com/i6869774/6559bb2670acd7dd.png)
调用刚刚定义的函数:
![](https://img.haomeiwen.com/i6869774/8090c377965f3249.png)
在 Xcode 上,Product || Analyze, 输出结果:
![](https://img.haomeiwen.com/i6869774/40a3ac76a2a568d8.png)
在静态分析器上,可以看到。静态分析器,提示第一步,假设 p 是空指针;第二步,空指针p 会做为 nonull 参数(第三个参数)。
所以用蓝色,提示你,这里可能会有 bug。静态分析器采用源码方式校验,文件多了的时候,使用它会很慢。但是很值得程序员去使用。
也可以设置返回值为 nonull类型:
![](https://img.haomeiwen.com/i6869774/7e577d5a37970edd.png)
1.2 Objective-C 语言的空指针校验
目前最新的 Objective-C 支持 nonnull, nullable 关键字。
增加一个 Objective-C 的对象:
![](https://img.haomeiwen.com/i6869774/48810ea824a7c58d.png)
nonnull 不能为空,如果传入一个nil 对象。Xcode 会友好地向程序员发出警告(黄色的):
![](https://img.haomeiwen.com/i6869774/15102df7bcf0a804.png)
如果创建一个 view 为nil, 使用 createView 消息获取一个新的 View。
这种场景与 tableview dequeue 消息一样:
![](https://img.haomeiwen.com/i6869774/269e064316b19bcc.png)
从 6.0 之后,就可以使用下面的方法,table view 控件会创建一个 cell 返回给你。
上面的方法有可能返回 nil。
__kindof 表示 本类或者其子类。返回值为这种类型,调用时,如果返回子类,直接声明子类类型,不用进行向下类型转换(down-cast)。
2. Objective-C 中 消息和枚举类型的弃用
在Objective-C中的消息和枚举类型中,可以使用 deprecated 特性。让过期弃用的方法和状态不被调用。
在 objc-api.h 的上有以下宏定义,方便程序员调用。当然也可以不使用这些宏,直接调用。
![](https://img.haomeiwen.com/i6869774/a23391a77f594ebc.png)
在 ARC 和 Swift上也有两个宏定义:
![](https://img.haomeiwen.com/i6869774/89cfb8b3985833f6.png)
2.1 C Objective-C 消息弃用
定义一个类,并声明三个方法:
![](https://img.haomeiwen.com/i6869774/231cf25829e33983.png)
调用 deprecated 枚举,在语法提示上中间会有一条红线。选择后,给出黄色警告。
![](https://pic1.zhimg.com/v2-ba115b6515d665770491babf47405760_b.png)
2.3 C 函数弃用
也可以使某一个C 语言函数设置为弃用的函数。
![](https://pic2.zhimg.com/v2-7ac97eb22d76add1457cdf84dbbf5321_b.png)
调用 deprecated C函数,跟其他弃用的方法或枚举,在语法提示上中间会有一条红线。选择后,给出黄色警告。
![](https://pic1.zhimg.com/v2-5bcff2b55cf3197ef78f39b37be159ac_b.png)
3. Objective-C 中 类相关好用的特性
工作中,有时候会出现需要使用密封类(不可继承)、混淆类名、提醒子类要调用父类方法的场景。
3.1 C Objective-C 可以使用 category 的密封类
定义一个密封类,使用编译器不让子类编译达到效果:
![](https://pic4.zhimg.com/v2-66c0e0f6122a5fc8d9b214b0d50a73ab_b.png)
定义一个子类,继承上面定义的父类:
![](https://pic1.zhimg.com/v2-8bb887d5973b157618ef1eeea7899780_b.png)
编译器会给出一个红色错误提示,不能继承,并且无法编译通过。
但是可以使用 category,增加相关的功能。
![](https://pic2.zhimg.com/v2-74747e08be52aec6989195828b891d45_b.png)
3.2 C Objective-C 指定子类实现某个方法时候,一定要调用父类方法。
通常我们在定义一个父类时,希望子类一定要调用父类方法时,能够给定义子类的程序员一个提示,减少出错。比如 UIViewController, viewDidLoad 方法就没有指定。但是我们需要调用父类。
定义一个父类,并指定子类在实现getData方法时需要调用父类的 getData 方法。
![](https://pic2.zhimg.com/v2-1a04a95ac8863ecce2b1a4b82b805535_b.png)
子类继承这个父类:
![](https://pic2.zhimg.com/v2-28bfeece0aacde12970899dda8638be5_b.png)
在子类的方法实现上,可以看到黄色提示,这样是不是特别的人性化呢。
![](https://pic3.zhimg.com/v2-7278430a9589d81f2539c7cb08194062_b.png)
3.3 C Objective-C 不能使用category的密封类
还有一种方式实现密封类,并且还不能使用 category 扩展功能。
在上面的类上增加一条扩展:
![](https://pic1.zhimg.com/v2-a1fcd3a0346e415c422b7344c2166de8_b.png)
查看子类,红色错误提示:
![](https://pic2.zhimg.com/v2-96c08b0d68d6d19dc7429f49c8602ec9_b.png)
并且新建一个 category, 并且编译:
![](https://pic2.zhimg.com/v2-2218d9a18e7d9838b6d1d598b225be29_b.png)
3.4 C Objective-C 混淆类名。
Objective-C runtime 特性,可以很方便的从一个对象上,返回该对象的类名。
有时候,为了私密性,我们需要隐藏真实的类名,给一个混淆后的类名。
定义一个类,并且指定其运行时的类名为苹果茄子蘑菇:
![](https://pic1.zhimg.com/v2-b6356be36d64668525700b87fd42e65c_b.png)
运行时,查看其类名:
![](https://pic2.zhimg.com/v2-73303c4d6787d7db7eecdd2f1028fce9_b.png)
4. C语言有趣的扩展
有时候,我们想重载C 函数。很无奈的是,当使用纯 C 编程的时候,无法重载方法。
4.1 C 函数重载 (overload)
定义一组日志打印方法,Xcode 检查到是 C 语言,无法使用函数重载,红色错误提示,编译不过:
![](https://pic2.zhimg.com/v2-a9d20b5cec82015323656082e2df8e01_b.png)
使用 overloadable 特性:
![](https://pic3.zhimg.com/v2-3bc0a814b3bf0380bb740925e1f3013a_b.png)
在方法定义上也需要加上:
![](https://pic3.zhimg.com/v2-c807a25dabeba0b5f4ca8cc8679ea622_b.png)
很方便的调用这组方法:
![](https://pic1.zhimg.com/v2-d71e6632465dcb8314d418e26e415fac_b.png)
4.2 C 函数参数静态校验
enable_if 特性可以函数传入某个参数,在编译期检查出来,如果在范围之内,放行通过。
![](https://pic1.zhimg.com/v2-a98ef7470d92ed8608d11680f88c9b50_b.png)
如果校验失败,会有红色错误提示:
![](https://pic4.zhimg.com/v2-6b6d740f0b09f712560c47f7a34ae93f_b.png)
4.3 Objective-C @(...)语法糖
将一个结构体或者联合,采用@(...),box 成一个 NSValue 对象。
先定义一个结构体,一个联合:
![](https://pic1.zhimg.com/v2-f9d6b4fa68e6b4eba7434d04e0623524_b.png)
将其使用 @(...)语法糖
![](https://pic2.zhimg.com/v2-9e515693fb04d46097ef1e8fd15af485_b.png)
4.4 main 函数之前与之后的事件处理
在进入 main 函数之前和之后进行一些初始化和收尾工作。在 iOS 应用程序上,它要比 + load()方法之后。
![](https://pic2.zhimg.com/v2-b9462ac8c9803f6b6ac1951a77bd06c9_b.png)
通常我们在 app 将要结束的时候做一些操作,applicationWillTerminate消息中处理(比之靠前)。也可以设置 main函数后处理一些清理工作。
![](https://pic2.zhimg.com/v2-b8e654e854e3ad6c36ca33827ff9207d_b.png)
参考:
常见的一些 attributeattribute 的参考文档annotations一篇关于 attribute 的博客(2014年的,有点旧)
网友评论