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。