我的理解Runtime就是:
1)淫奔、一套用C/C++和匯編實現的一套API
OC就是運行時機制滨彻,其中最主要的是消息機制盾饮。
對于C語言废亭,函數的調用在編譯的時候會決定調用哪個函數缘圈;
對于OC的函數靴拱,屬于動態(tài)調用過程国觉,在編譯的時候并不能決定真正調用哪個函數,只有在真正運行的時候才會根據函數的名稱找到對應的函數來調用又憨。
2)冒晰、OC 是一個全動態(tài)語言,OC 的一切都是基于 Runtime 實現的
平時編寫的OC代碼, 在程序運行過程中, 其實最終都是轉成了runtime的C語言代碼, runtime算是OC的幕后工作者
舉例:
[[Person alloc] init]
runtime :
objc_msgSend(objc_msgSend("Person" , "alloc"), "init")
一竟块、數據結構:
objc_object,objc_class耐齐,isa浪秘,class_data_bits_t,cache_t埠况,method_t
objc_object(id)
isa_t:關于isa操作相關耸携,弱引用相關,關聯對象相關辕翰,內存管理相關
objc_class (class) :繼承自objc_object
isa指向:
關于對象夺衍,其指向類對象。
關于類對象喜命,其指向元類對象沟沙。
實例--(isa)-->class--(isa)-->MetaClass
cache_t:用于快速查找方法執(zhí)行函數,是可增量擴展的哈希表結構壁榕,是局部性原理的最佳運用
method_t:
函數四要素:名稱矛紫,返回值,參數牌里,函數體
struct method_t {
SEL name; //名稱
const char *types;//返回值和參數
IMP imp; //函數體
}
二颊咬、對象,類對象牡辽,元類對象
類對象存儲實例方法列表等信息喳篇。
元類對象存儲類方法列表等信息。
三态辛、消息傳遞的流程:(如何通過selector找到對應的IMP地址)
緩存查找-->當前類查找-->父類逐級查找
1.調用方法之前麸澜,先去查找緩存,看看緩存中是否有對應選擇器的方法實現因妙,如果有痰憎,就去調用函數票髓,完成消息傳遞(緩存查找:給定值SEL,目標是查找對應bucket_t中的IMP,哈希查找)
2.如果緩存中沒有铣耘,會根據當前實例的isa指針查找當前類對象的方法列表洽沟,看看是否有同樣名稱的方法 ,如果找到蜗细,就去調用函數裆操,完成消息傳遞(當前類中查找:對于已排序好的方法列表,采用二分查找炉媒,對于沒有排序好的列表踪区,采用一般遍歷)
3.如果當前類對象的方法列表沒有,就會逐級父類方法列表中查找吊骤,如果找到缎岗,就去調用函數,完成消息傳遞(父類逐級查找:先判斷父類是否為nil白粉,為nil則結束传泊,否則就繼續(xù)進行緩存查找-->當前類查找-->父類逐級查找的流程)
4.如果一直查到根類依然沒有查找到,則進入到消息轉發(fā)流程中鸭巴,完成消息傳遞
舉例:
下面以實例對象調用方法[blackDog walk]為例描述方法調用的流程
1)眷细、編譯器會把`[blackDog walk]`轉化為`objc_msgSend(blackDog,SEL)`鹃祖,SEL為@selector(walk)溪椎。
2)、Runtime會在blackDog對象所對應的Dog類的方法緩存列表里查找方法的SEL
3)恬口、如果沒有找到校读,則在Dog類的方法分發(fā)表查找方法的SEL。(類由對象isa指針指向楷兽,方法分發(fā)表即methodList)
4)地熄、如果沒有找到,則在其父類(設Dog類的父類為Animal類)的方法分發(fā)表里查找方法的SEL(父類由類的superClass指向)
5)芯杀、如果沒有找到端考,則沿繼承體系繼續(xù)下去,最終到達NSObject類揭厚。
6)却特、如果在234的其中一步中找到,則定位了方法實現的入口筛圆,執(zhí)行具體實現
7)裂明、如果最后還是沒有找到,會面臨兩種情況:``(1) 如果是使用`[blackDog walk]`的方式調用方法````(2) 使用`[blackDog performSelector:@selector(walk)]`的方式調用方法
四太援、消息轉發(fā):
1)闽晦、動態(tài)方法解析
接收到未知消息時(假設blackDog的walk方法尚未實現)扳碍,runtime會調用+resolveInstanceMethod:(實例方法)或者+resolveClassMethod:(類方法)
2)、備用接收者
如果以上方法沒有做處理仙蛉,runtime會調用- (id)forwardingTargetForSelector:(SEL)aSelector方法笋敞。
如果該方法返回了一個非nil(也不能是self)的對象,而且該對象實現了這個方法荠瘪,那么這個對象就成了消息的接收者夯巷,消息就被分發(fā)到該對象。
適用情況:通常在對象內部使用哀墓,讓內部的另外一個對象處理消息趁餐,在外面看起來就像是該對象處理了消息。
比如:blackDog讓女朋友whiteDog來接收這個消息
3)篮绰、完整消息轉發(fā)
在- (void)forwardInvocation:(NSInvocation *)anInvocation方法中選擇轉發(fā)消息的對象后雷,其中anInvocation對象封裝了未知消息的所有細節(jié),并保留調用結果發(fā)送到原始調用者吠各。
比如:blackDog將消息完整轉發(fā)給主人dogOwner來處理
五喷面、應用
1、發(fā)送消息
方法調用的本質走孽,就是讓對象發(fā)送消息。
objc_msgSend,只有對象才能發(fā)送消息琳状,因此以objc開頭.
使用消息機制前提磕瓷,必須導入#import <objc/message.h>
2、交換方法
3念逞、類\對象的關聯對象
4困食、動態(tài)添加方法
5、字典轉模型KVC實現