1. 数据结构
(1) id <=> objc_object
[isa_t
, ]
(2) Class <=> objc_class
(继承objc_object
) [1.Class superClass
, 2.cache_t cache
, 3.class_data_bits_t bits
]
(3) isa
指针
- 指针型isa, isa的值代表Class的地址
- 非指针型isa, isa的值的部分代表Class的地址
(4) isa
指向
- 对象实例的isa指向 类对象
- 类的isa指向 原类对象
(5) cache_t
- 用于快速查找方法执行函数
- 是可增量扩展的哈希表结构
- 是局部性原理的最佳应用
(6) class_data_bit_t
class_data_bit_t
主要是对class_rw_t
的封装class_rw_t
代表了类的相关读写信息, 对class_ro_t
的封装class_ro_t
代表类的只读信息
(7) class_rw_t
methods
properties
protocols
(8) class_ro_t
name
method
ivars
properties
protocols
2. 对象, 类对象, 元类对象
- 类对象 存储实例方法列表等信息
- 元类对象 存储类方法列表等信息
3. 消息传递
1 | void objc_msgSend(void /*id self, SEL op, ...*) |
- 缓存查找
- 当前类方法列表查找
- 逐级父类方法列表查找
- 消息转发流程
缓存查找
- 给定方法选择器(SEL), 查找(hash查找)方法对应的实现(bucket_t中的IMP)
当前类中查找
- 对于已排序好的列表, 采用二分查找方法对应执行函数
- 对于没有排序的列表, 采用一般遍历查找方法对应的执行函数
父类逐级查找
- 判断当前类父类是否为nil (如果父类为nil, 当前类就是NSObject, 直接结束; 否则2.)
- 缓存查找 (查找到结束, 否则3.)
- 方法列表查找
4. 消息转发
resolveInstanceMethod:
(区分实例方法和类方法,resolveInstanceMethod
/resolveClassMethod
返回YES, 消息已处理; 否则2.)forwardingTargetForSelector:
(返回转发目标, 消息已处理; 否则返回为nil, 3.)methodSignatureForSelector:
(返回方法签名执行4.; 否则返回nil, 消息无法处理)forwardInvocation:
(能处理就结束, 否则消息无法处理crash)
5. Method-Swizzling
1 | // (`SEL1 -> IMP1`, `SEL2 -> IMP2`) => (`SEL1 -> IMP2`, `SEL2 -> IMP1`) |
6. 添加动态方法
resolveInstanceMethod:
// 内部添加下面apiclass_addMethod(self, sel, imp, "v@:");
动态方法解析 @dynamic
- 动态运行时语言将函数决议推迟到运行时.
- 编译时语言在编译期进行函数决议.
总结
- [obj foo]和objc_msgSend()函数之间的关系
1 | // 消息传递 |
- runtime通过Selector如何找到对应的IMP地址
1 | 当前类查找, 缓存, 方法列表 是否有IMP的实现; |
- 能否向编译后的类增加实例变量
1 | 编译后的类不能增加实例变量, |
- 本文作者: 醉疏狂
- 本文链接: https://hubin97.github.io/2020/05/20/Runtime/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!