转自:https://zhuanlan.zhihu.com/p/25876528
Objective-C 中 空指针校验
Objective-C 是 C 的超集,在日常编程中,会使用一些 C 语言代码。 需要对 C 语言和 Objective-C分别讨论。
1.1 C 语言的空指针校验
在传入某个函数内,检查某个指针是否为空。通常使用断言assert。
这里要介绍一个 xcode 静态分析器上的功能。
可以将 C 语言空指针调用找出来。
这里的nonnull表示,不能为空。1,3表示,第一个参数和第三个参数是不能为空指针的。如果传入空指针,编译通过,运行时报错。使用静态分析器会提示你,这里使用了空指针。
在NullPointerCheck.m 上两个函数的定义:
调用刚刚定义的函数:
在 Xcode 上,Product || Analyze, 输出结果:
在静态分析器上,可以看到。静态分析器,提示第一步,假设 p 是空指针;第二步,空指针p 会做为 nonull 参数(第三个参数)。
所以用蓝色,提示你,这里可能会有 bug。静态分析器采用源码方式校验,文件多了的时候,使用它会很慢。但是很值得程序员去使用。
也可以设置返回值为 nonull类型:
1.2 Objective-C 语言的空指针校验
目前最新的 Objective-C 支持 nonnull, nullable 关键字。
增加一个 Objective-C 的对象:
nonnull 不能为空,如果传入一个nil 对象。Xcode 会友好地向程序员发出警告(黄色的):
如果创建一个 view 为nil, 使用 createView 消息获取一个新的 View。
这种场景与 tableview dequeue 消息一样:
从 6.0 之后,就可以使用下面的方法,table view 控件会创建一个 cell 返回给你。
上面的方法有可能返回 nil。
__kindof 表示 本类或者其子类。返回值为这种类型,调用时,如果返回子类,直接声明子类类型,不用进行向下类型转换(down-cast)。
2. Objective-C 中 消息和枚举类型的弃用
在Objective-C中的消息和枚举类型中,可以使用 deprecated 特性。让过期弃用的方法和状态不被调用。
在 objc-api.h 的上有以下宏定义,方便程序员调用。当然也可以不使用这些宏,直接调用。
在 ARC 和 Swift上也有两个宏定义:
2.1 C Objective-C 消息弃用
定义一个类,并声明三个方法:
调用 deprecated 修饰的方法,在语法提示上(弹窗)消息中间会有一条红线。选择后,给出黄色警告提示,可以编译:
调用 unavailable 修饰的方法,在语法提示上找不到。手动输入后,给出红色错误,无法编译。
2.2 C Objective-C 枚举弃用
在开发过程中,我们会大量使用枚举,定义各种状态。有的时候,有些状态因为业务等原因已经弃用。
定义一个枚举类型:
调用 deprecated 枚举,在语法提示上中间会有一条红线。选择后,给出黄色警告。
2.3 C 函数弃用
也可以使某一个C 语言函数设置为弃用的函数。
调用 deprecated C函数,跟其他弃用的方法或枚举,在语法提示上中间会有一条红线。选择后,给出黄色警告。
3. Objective-C 中 类相关好用的特性
工作中,有时候会出现需要使用密封类(不可继承)、混淆类名、提醒子类要调用父类方法的场景。
3.1 C Objective-C 可以使用 category 的密封类
定义一个密封类,使用编译器不让子类编译达到效果:
定义一个子类,继承上面定义的父类:
编译器会给出一个红色错误提示,不能继承,并且无法编译通过。
但是可以使用 category,增加相关的功能。
3.2 C Objective-C 指定子类实现某个方法时候,一定要调用父类方法。
通常我们在定义一个父类时,希望子类一定要调用父类方法时,能够给定义子类的程序员一个提示,减少出错。比如 UIViewController, viewDidLoad 方法就没有指定。但是我们需要调用父类。
定义一个父类,并指定子类在实现getData方法时需要调用父类的 getData 方法。
子类继承这个父类:
在子类的方法实现上,可以看到黄色提示,这样是不是特别的人性化呢。
3.3 C Objective-C 不能使用category的密封类
还有一种方式实现密封类,并且还不能使用 category 扩展功能。
在上面的类上增加一条扩展:
查看子类,红色错误提示:
并且新建一个 category, 并且编译:
3.4 C Objective-C 混淆类名。
Objective-C runtime 特性,可以很方便的从一个对象上,返回该对象的类名。
有时候,为了私密性,我们需要隐藏真实的类名,给一个混淆后的类名。
定义一个类,并且指定其运行时的类名为苹果茄子蘑菇:
运行时,查看其类名:
4. C语言有趣的扩展
有时候,我们想重载C 函数。很无奈的是,当使用纯 C 编程的时候,无法重载方法。
4.1 C 函数重载 (overload)
定义一组日志打印方法,Xcode 检查到是 C 语言,无法使用函数重载,红色错误提示,编译不过:
使用 overloadable 特性:
在方法定义上也需要加上:
很方便的调用这组方法:
4.2 C 函数参数静态校验
enable_if 特性可以函数传入某个参数,在编译期检查出来,如果在范围之内,放行通过。
如果校验失败,会有红色错误提示:
4.3 Objective-C @(...)语法糖
将一个结构体或者联合,采用@(...),box 成一个 NSValue 对象。
先定义一个结构体,一个联合:
将其使用 @(...)语法糖
4.4 main 函数之前与之后的事件处理
在进入 main 函数之前和之后进行一些初始化和收尾工作。在 iOS 应用程序上,它要比 + load()方法之后。
通常我们在 app 将要结束的时候做一些操作,applicationWillTerminate消息中处理(比之靠前)。也可以设置 main函数后处理一些清理工作。
参考:
常见的一些 attributeattribute 的参考文档annotations一篇关于 attribute 的博客(2014年的,有点旧)
示例代码:SwiftZimu/ObjCAttribute