在Objective-C中傲醉,message與方法的真正實現(xiàn)是在執(zhí)行階段綁定的,而非編譯階段。編譯器會將消息發(fā)送轉換成對objc_msgSend方法的調用。
objc_msgSend方法含兩個必要參數(shù):receiver死姚、方法名(即:selector),如:
[receiver message]; 將被轉換為:objc_msgSend(receiver, selector);
objc_msgSend方法也能hold住message的參數(shù)勤篮,如:
objc_msgSend(receiver, selector, arg1, arg2, …);
objc_msgSend方法會做按照順序進行以下操作都毒,以完成動態(tài)綁定:
- 1.查找selector所指代的程序(方法的真正實現(xiàn))。因為不同類對同一方法有不同的實現(xiàn)碰缔,所以對方法的真正實現(xiàn)的查找依賴于receiver的類.
- 2.調用該實現(xiàn)账劲,并將一系列參數(shù)傳遞過去.
- 3.將該實現(xiàn)的返回值作為自己的返回值,返回之.
消息傳遞的關鍵是金抡,編譯器構建每個類和對象時所采用的數(shù)據(jù)結構涤垫。每個類都包含以下兩個必要元素:
- 一個指向父類的指針
- 一個調度表(dispatch table)。該調度表將類的selector與方法的實際內存地址關聯(lián)起來
每個對象都有一個指向所屬類的指針isa竟终。通過該指針,對象可以找到它所屬的類切蟋,也就找到了其全部父類统捶,如下圖所示:
當向一個對象發(fā)送消息時,objc_msgSend方法根據(jù)對象的isa指針找到對象的類柄粹,然后在類的調度表(dispatch table)中查找selector喘鸟。如果無法找到selector,objc_msgSend通過指向父類的指針找到父類驻右,并在父類的調度表(dispatch table)中查找selector什黑,以此類推直到NSObject類。一旦查找到selector堪夭,objc_msgSend方法根據(jù)調度表的內存地址調用該實現(xiàn)愕把。 通過這種方式,message與方法的真正實現(xiàn)在執(zhí)行階段才綁定森爽。
為了保證消息發(fā)送與執(zhí)行的效率恨豁,系統(tǒng)會將全部selector和使用過的方法的內存地址緩存起來。每個類都有一個獨立的緩存爬迟,緩存包含有當前類自己的 selector以及繼承自父類的selector橘蜜。查找調度表(dispatch table)前,消息發(fā)送系統(tǒng)首先檢查receiver對象的緩存付呕。
緩存命中的情況下计福,消息發(fā)送(messaging)比直接調用方法(function call)只慢一點點跌捆。