iOS Runtime 初识与应用

栏目: Objective-C · 发布时间: 5年前

内容简介:什么是运行时呢?从字面意思来看,就是一个程序在其运行的过程中所做的一些事情。而苹果在 object—C 中提供了一套纯 c 语言的 api,这套 api 即为 runtime。在 iOS 开发的过程中,正式因为runtime 的特性,让 object-C 具有了吸引人的魅力。使得我们可以真正做到玩语言,做出高逼格的花样,快乐就完了~看完上面的流程,可能会迷惑里面提到的一下字端是什么意思,那我们来看一下一个 OC 类中都包含了什么?

什么是运行时呢?从字面意思来看,就是一个程序在其运行的过程中所做的一些事情。而苹果在 object—C 中提供了一套纯 c 语言的 api,这套 api 即为 runtime。

在 iOS 开发的过程中,正式因为runtime 的特性,让 object-C 具有了吸引人的魅力。使得我们可以真正做到玩语言,做出高逼格的花样,快乐就完了~

要了解运行时,我们得先了解 object-C 的消息机制,可以看下面的流程:

1、编译器会先将代码 [obj doSomeThing] 转化为 objc_msgSend(obj, @selector (doSomeThing)) 函数去执行。
2、在 objc_msgSend() 函数中,首先通过 obj 的 isa 指针找到 obj 对应的 class。
3、在 class 中会先去 cache 中 通过 SEL 查找对应函数 doSomeThing(cache 中method 列表是以 SEL 为 key 通过 hash 表来存储的,这样能提高函数查找速度),若 cache 中未找到。再去 class 中的消息列表 methodList 中查找,若 methodList 中未找到,则取 superClass 中查找。若能找到,则将 doSomeThing 加入到 cache中,以方便下次查找,并通过 method 中的函数指针跳转到对应的函数中去执行。

看完上面的流程,可能会迷惑里面提到的一下字端是什么意思,那我们来看一下一个 OC 类中都包含了什么?

iOS Runtime 初识与应用

可以先看类结构体 struct objc_class。虽然该结构体中有许多变量,但是从变量名中我们可以大概理解其含义,结构体里包含了 指像父类的指针、类名、版本等等信息,里面有些变量会在下面的应用中进行用到。

下面就让我们来看看 runtime 的具体应用吧~

Runtime 的应用

Runtime 的功能非常强大,这也是魅力所在,它能够在程序运行的时候,获取一个类中的所有信息,并且能够根据开发者意愿去修改。脑洞多大,变化就能多大~

接下来,本文主要就下面几点进行讲解:

(1)使用 class_addMethod 函数在运行时对函数进行动态增加新函数

(2)消息转发

(3)使用 class_copyPropertyList 及 property_getName 获取类的属性列表及每个属性的名称

(4) 使用 class_copyMethodList 获取类的所有方法列表

(5) Method Swizzling

动态添加方法 - class_addMethod

首先来看一下 API 文档解释

iOS Runtime 初识与应用

先看下函数中的各个参数的含义:

Class _Nullable cls:传入的是一个类,也就是你想要在哪个类里进行添加方法

SEL _Nollnull name:想要添加的方法名字

IMP _Nonnull imp:imp 是 Implement 缩写,表示指向方法的实现地址

const char * _Nonnull types:对于参数与返回值的描述。举个例子:"v@:",表示的是返回值为 void 并且没有参数。

下面看一下具体的调用:

iOS Runtime 初识与应用

这里要给 HJXPerson 类动态添加一个 sayHello 的方法。首先要拿到添加的方法 sayHello 的 IMP 指针,然后调用相应的接口去添加方法。

(注:当要执行动态添加方法的时候,需要用 performSelector 来进行调用,因为 performSelector 是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验)

消息转发

文章开头介绍了 Objective-C 中调用一个方法的流程,但如果最后都没有找到对应方法,我们的程序都会 crash 并抛出信息没有找到对应的方法。其实在 crash 之前还会进行一套流程,那就是消息转发。转发流程图如下:

iOS Runtime 初识与应用

下面将分别结合代码事例进行介绍这几种方法的处理:

  • resolveInstanceMethod

此为消息转发的先导,也叫动态决议机制。见下面例子:

iOS Runtime 初识与应用

在 HJXPerson 类中并没有声明 eat 这个函数,所以在实例调用方法的时候会进入到这个回调之中。

其实,objective-c 的方法就是至少带有两个参数(self 和 cmd)的普通的 C 函数。因此在代码中提供这样一个 C 函数 dynamicMethodIMPEat,让它来充当对象方法 eat 这个 selector 的动态实现。

因为 eat 是被对象所调用,所以它被认为是一个对象方法,因而应该在 resolveInstanceMethod 方法中为其提供实现。

  • forwardingTargetForSelector

这个方法只能让我们把消息转发到另一个能处理这个消息的对象,但是无法处理消息的内容,比如参数和返回值。例子如下:

iOS Runtime 初识与应用

该类为 HJXCat 类,里面声明了 “useTool” 这个方法但并没有实现,所以在未添加 resolveInstanceMethod 处理的时候,会进入到 forwardingTargetForSelector 方法中,然后可以根据传入的 aSelector,来转交给其他类去处理相应的方法。

(注:返回的为想要把方法交给的类的一个实例对象)

  • forwardInvocation

先看下工程代码

iOS Runtime 初识与应用

forwardInvocation 的整体流程和 forwardingTargetForSelector 基本上是差不多的。通过 aSelector 来进行判断是否要进行转发,然后进行手动签名。然后在 anInvocation 中可以获取到函数传里过程中所有信息。

forwardingTargetForSelector 和 forwardInvocation 区别:

快速转发: forwardingTargetForSelector 仅支持一个对象的返回,也就是说消息只能被转发给一个对象、无法处理消息的内容,比如参数和返回值。

普通转发: forwardInvocation 可以将消息同时转发给任意多个对象。

消息转发总结

  • 首先看是否为该 selector 提供了动态方法决议机制,如果提供了则转到 2;如果没有提供则转到 3;

  • 如果动态方法决议真正为该 selector 提供了实现,那么就调用该实现,完成消息发送流程,消息转发就不会进行了;如果没有提供,则转到 3;

  • 其次看是否为该 selector 提供了消息转发机制,如果提供了消息了则进行消息转发,此时,无论消息转发是怎样实现的,程序均不会 crash。(因为消息调用的控制权完全交给消息转发机制处理,即使消息转发并没有做任何事情,运行也不会有错误,编译器更不会有错误提示。);如果没提供消息转发机制,则转到 4;

  • 运行报错:无法识别的 selector,程序 crash

property_getName 及 class_copyMethodList

这两个函数总从字面意思上,可以看出分别是获取一个类中的所有属性名称及方法名。这两个方法可以算是基础,让你可以知道一个类内的所有属性及方法,以便你接下来可以随心所欲的对于其修改,修改哪里。

下面为调用方法来获取 HJXCat 中的属性及方法:

iOS Runtime 初识与应用
iOS Runtime 初识与应用

(上面的各个属性都是声明在 .m 文件中的)

iOS 黑魔法 - Method Swizzling

首先让我们来看下方法交换的原理:

  • 在 Objective-C 中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是 selector 的名字。利用 Objective-C 的动态特性,可以实现在运行时偷换 selector 对应的方法实现,达到给方法挂钩的目的。

  • 每个类都有一个方法列表,存放着 selector 的名字和方法实现的映射关系。IMP 有点类似函数指针,指向具体的 Method 实现。

归根结底,都是偷换了 selector 的 IMP

跟消息转发相比,Method Swizzling 的做法更为隐蔽,甚至有些冒险,也增大了debug的难度。

下面我们来看一下代码部分:

iOS Runtime 初识与应用

就这么简简单单几行,就能够实现方法的交换。原有的 eat 方法在调用 hasEatenFull 方法后,就与 play 方法进行了交换,再次执行 eat 方法,其实就是调用了 play 方法。

虽然 Swizzling 可以任你喜欢的去弄,想要玩起来,anyway,都可以。但是开发工程中,我们需要先好好的去想一想,能不能利用良好的代码和架构设计来实现,或者是深入语言的特性来实现。好用,但是不能滥用。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Text Processing in Python

Text Processing in Python

David Mertz / Addison-Wesley Professional / 2003-6-12 / USD 54.99

Text Processing in Python describes techniques for manipulation of text using the Python programming language. At the broadest level, text processing is simply taking textual information and doing som......一起来看看 《Text Processing in Python》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码