Runtime 之 isa指针
111.png
1.横向看:实例是对象,类也是对象(类对象),meta类也是对象(原类对象)
这是很重要的一点,希望大家理解,我们这里忽略上下结构,先看左右结构,从左到右的指向就是之前介绍的runtime源码中objc_class结构里isa的指向,Instance指的是我们创建的对象,Subclass(class)就是创建该对象的那个类,注意:创建对象的类本身也是对象,称为类对象,类对象中存放的是描述实例相关的信息,例如实例的成员变量,实例方法。
类对象里的isa指针指向Subclass(meta),Subclass(meta)也是一个对象,是原类对象,原类对象中存放的是描述类相关的信息,例如类方法,在这一过程中,isa的两次指向很像很像,大家注意理解。
2.纵向看:
superclass指针很容易理解,就是按照继承关系向上指的,一直到继承链的最上方。
参考:为什么object_getClass(obj)与[OBJ class]返回的指针不同
实例方法class 和类方法class
- 类方法是在meta class里的,类方法就是把自己返回,而实例方法中是返回实例isa的类
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
Runtime 之一些方法
- objc_setAssociatedObject : 关联对象就是runTime界的NSMultableDictionary
iOS objc_setAssociatedObject 关联对象的学习 - class_getInstanceMethod
- method_getImplementation
Method targetMethod = class_getInstanceMethod(klass, selector);//函数的实例
IMP targetMethodIMP = method_getImplementation(targetMethod);//函数的实现
消息转发机制
消息转发机制
Aspects
-
aspects 流程
1)为对象增加一个关联关系:aspects__viewDidLoad关联内容是 aspectContainer
2)由对象 和 sel 生成一个identifier
3) 把identifier增加到container中
4.1)生成类_Aspects_AspectsViewController, _Aspects_AspectsViewController是 AspectsViewController的子类。
4.2)修改_Aspects_AspectsViewController的forwardInvocation函数的实现为_ASPECTS_ARE_BEING_CALLED_。
4.3)_Aspects_AspectsViewController增加方法__aspects_forwardInvocation,__aspects_forwardInvocation的实现为原forwardInvocation函数的实现。
4.4)修改对象原类,isa 指针由AspectsViewController 变成 _Aspects_AspectsViewController,。
5)给类_Aspects_AspectsViewController中增加方法aspects__viewDidLoad 其实现时 原viewDidLoad的实现
6)给类_Aspects_AspectsViewController 中的方法 viewDidLoad 的实现修改为_objc_msgForward
-
我们以在ViewControler的viewWillAppear:方法之后插入一段代码为例,来讲解hook前后的变化, 在没有hook之前,ViewController的SEL与IMP关系如下
222.png
333.png
然后,我们再来看看hook后,一个viewWillAppear:的实际调用顺序:
- object收到selector(viewWillAppear:)的消息
- 找到对应的IMP:_objc_msgForward,执行后触发消息转发机制。
- object收到forwardInvocation:消息
- 找到对应的IMP:ASPECTS_ARE_BEING_CALLED,执行IMP
- 向object对象发送aspects_viewWillAppear:,执行最初的viewWillAppear方法的IMP
- 执行插入的block代码
- 如果ViewController无法响应aspects_viewWillAppear,则向object对象发送__aspects_forwardInvocation:来执行最初的forwardInvocation IMP
- 所以,Aspects是采用了集中式的hook方式,所有的调用最后走的都是一个C函数ASPECTS_ARE_BEING_CALLED。