你可能不知道 Objective-C的特性

转自:https://zhuanlan.zhihu.com/p/25876528


Objective-C 中 空指针校验

Objective-C 是 C 的超集,在日常编程中,会使用一些 C 语言代码。 需要对 C 语言和 Objective-C分别讨论。

1.1 C 语言的空指针校验

在传入某个函数内,检查某个指针是否为空。通常使用断言assert。

这里要介绍一个 xcode 静态分析器上的功能。

可以将 C 语言空指针调用找出来。

你可能不知道 Objective-C的特性_第1张图片

这里的nonnull表示,不能为空。1,3表示,第一个参数和第三个参数是不能为空指针的。如果传入空指针,编译通过,运行时报错。使用静态分析器会提示你,这里使用了空指针。

在NullPointerCheck.m 上两个函数的定义:

你可能不知道 Objective-C的特性_第2张图片

调用刚刚定义的函数:

你可能不知道 Objective-C的特性_第3张图片

在 Xcode 上,Product || Analyze, 输出结果:

你可能不知道 Objective-C的特性_第4张图片

在静态分析器上,可以看到。静态分析器,提示第一步,假设 p 是空指针;第二步,空指针p 会做为 nonull 参数(第三个参数)。

所以用蓝色,提示你,这里可能会有 bug。静态分析器采用源码方式校验,文件多了的时候,使用它会很慢。但是很值得程序员去使用。

也可以设置返回值为 nonull类型:

1.2 Objective-C 语言的空指针校验

目前最新的 Objective-C 支持 nonnull, nullable 关键字。

增加一个 Objective-C 的对象:

你可能不知道 Objective-C的特性_第5张图片

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 的上有以下宏定义,方便程序员调用。当然也可以不使用这些宏,直接调用。

你可能不知道 Objective-C的特性_第6张图片

在 ARC 和 Swift上也有两个宏定义:

你可能不知道 Objective-C的特性_第7张图片

2.1 C Objective-C 消息弃用

定义一个类,并声明三个方法:

你可能不知道 Objective-C的特性_第8张图片

调用 deprecated 修饰的方法,在语法提示上(弹窗)消息中间会有一条红线。选择后,给出黄色警告提示,可以编译:

调用 unavailable 修饰的方法,在语法提示上找不到。手动输入后,给出红色错误,无法编译。

2.2 C Objective-C 枚举弃用

在开发过程中,我们会大量使用枚举,定义各种状态。有的时候,有些状态因为业务等原因已经弃用。

定义一个枚举类型:

你可能不知道 Objective-C的特性_第9张图片

调用 deprecated 枚举,在语法提示上中间会有一条红线。选择后,给出黄色警告。

2.3 C 函数弃用

也可以使某一个C 语言函数设置为弃用的函数。

调用 deprecated C函数,跟其他弃用的方法或枚举,在语法提示上中间会有一条红线。选择后,给出黄色警告。

3. Objective-C 中 类相关好用的特性

工作中,有时候会出现需要使用密封类(不可继承)、混淆类名、提醒子类要调用父类方法的场景。

3.1 C Objective-C 可以使用 category 的密封类

定义一个密封类,使用编译器不让子类编译达到效果:

你可能不知道 Objective-C的特性_第10张图片

定义一个子类,继承上面定义的父类:

你可能不知道 Objective-C的特性_第11张图片

编译器会给出一个红色错误提示,不能继承,并且无法编译通过。

但是可以使用 category,增加相关的功能。

你可能不知道 Objective-C的特性_第12张图片

3.2 C Objective-C 指定子类实现某个方法时候,一定要调用父类方法。

通常我们在定义一个父类时,希望子类一定要调用父类方法时,能够给定义子类的程序员一个提示,减少出错。比如 UIViewController, viewDidLoad 方法就没有指定。但是我们需要调用父类。

定义一个父类,并指定子类在实现getData方法时需要调用父类的 getData 方法。

你可能不知道 Objective-C的特性_第13张图片

子类继承这个父类:

你可能不知道 Objective-C的特性_第14张图片

在子类的方法实现上,可以看到黄色提示,这样是不是特别的人性化呢。

3.3 C Objective-C 不能使用category的密封类

还有一种方式实现密封类,并且还不能使用 category 扩展功能。

在上面的类上增加一条扩展:

查看子类,红色错误提示:

并且新建一个 category, 并且编译:

3.4 C Objective-C 混淆类名。

Objective-C runtime 特性,可以很方便的从一个对象上,返回该对象的类名。

有时候,为了私密性,我们需要隐藏真实的类名,给一个混淆后的类名。

定义一个类,并且指定其运行时的类名为苹果茄子蘑菇:

你可能不知道 Objective-C的特性_第15张图片

运行时,查看其类名:

4. C语言有趣的扩展

有时候,我们想重载C 函数。很无奈的是,当使用纯 C 编程的时候,无法重载方法。

4.1 C 函数重载 (overload)

定义一组日志打印方法,Xcode 检查到是 C 语言,无法使用函数重载,红色错误提示,编译不过:

你可能不知道 Objective-C的特性_第16张图片

使用 overloadable 特性:

你可能不知道 Objective-C的特性_第17张图片

在方法定义上也需要加上:

你可能不知道 Objective-C的特性_第18张图片

很方便的调用这组方法:

你可能不知道 Objective-C的特性_第19张图片

4.2 C 函数参数静态校验

enable_if 特性可以函数传入某个参数,在编译期检查出来,如果在范围之内,放行通过。

你可能不知道 Objective-C的特性_第20张图片

如果校验失败,会有红色错误提示:

你可能不知道 Objective-C的特性_第21张图片

4.3 Objective-C @(...)语法糖

将一个结构体或者联合,采用@(...),box 成一个 NSValue 对象。

先定义一个结构体,一个联合:

你可能不知道 Objective-C的特性_第22张图片

将其使用 @(...)语法糖

你可能不知道 Objective-C的特性_第23张图片

4.4 main 函数之前与之后的事件处理

在进入 main 函数之前和之后进行一些初始化和收尾工作。在 iOS 应用程序上,它要比 + load()方法之后。

你可能不知道 Objective-C的特性_第24张图片

通常我们在 app 将要结束的时候做一些操作,applicationWillTerminate消息中处理(比之靠前)。也可以设置 main函数后处理一些清理工作。

你可能不知道 Objective-C的特性_第25张图片

参考:

常见的一些 attributeattribute 的参考文档annotations一篇关于 attribute 的博客(2014年的,有点旧)

示例代码:SwiftZimu/ObjCAttribute

你可能感兴趣的:(你可能不知道 Objective-C的特性)