概述
Runtime 使用C和汇编编写的库.
OC拓展了C语言,并加入了 面向对象 和 消息传递机制, 而消息机制就是写在 Runtime 中.
C与OC函数调用区别
1. C 语言,函数调用在编译时就决定了调用哪个函数,编译完成后顺序执行
2. OC : 函数调用变成消息发送.属于动态调用.在编译时并不能决定调用哪个函数. 只有在运行的时候才会根据函数的名称找到对应的函数调用
Runtime 的具体实现
- OC并不能直接编译为汇编语言,而是要先转成纯C语言在进行编译和汇编操作,从OC到C语言的过度就是通过 Runtime 来实现的.
一个对象的方法像这样 [obj foo] 编译器转成消息发送 objc_msgSend(obj,foo)
-
Runtime时执行流程是这样的:
- 首先 通过 obj的 isa 指针找到它的 class
- 在class的 method list 找foo;(把常用的 method 存放到 objc_catch中,提高查找效率)
- 如果class中没有 foo,继续往它的superclass中找
- 一旦找到foo这个函数,就去执行它的实现IMP
但这种实现有个问题,效率低.但一个class 往往只是20%的函数会被经常调用,可能占总调用次数的80%.
-
消息传递的一些概念
- 类对象(objc_class) 由Class类型来表示,一个指向 objc_class结构体的指针
- 实例(objc_object)
- 元类(Meta Class)
- Method(objc_method)
- SEL (objc_selector)
- IMP
- 类缓存(objc_cache)
- Category(objc_category)
-
Runtime 的应用场景
- 关联对象给分类增加属性
- 方法魔法方法添加和替换 和KVO实现
- 消息转发(热更新)解决bug
- 实现NSCoding的自动归档和自动解档
- 实现字典和模型的自动转换
IOS
SEL: 类成员方法的指针,但不同于C语言的函数指针,函数指针直接保存了方法的地址,但是SEL知识方法编号
IMP: 一个函数指针,保存了方法的地址.
IMP 和 SEL关系
每个继承与 NSObject的类都能自动获取runtime的支持.在这样的一个类中,又一个isa指针,指向该类定义的数据结构体,这个结构体是由编译器编译时为类创建的. 在这个结构体中有包含了指向其他类定义的指针以及Dispatch table Dispathc table是一张SEL和IMP的对应表.
也就是说方法 SEL最后还是要通过Dispatch table 表寻找到对应的IMP,IMP就是一个函数指针,然后执行这个方法