//聯(lián)系人:石虎QQ: 1224614774昵稱:嗡嘛呢叭咪哄
一萧锉、OC 消息機制原理
/**
注意點:
??????? 1.在 OC 中柿隙,message與方法是在執(zhí)行階段綁定的,而不是編譯階段衩辟。
???????? 2.可以說[a func]這樣一個調(diào)用帆焕,在編譯階段,編譯器并不知道 func要執(zhí)行哪段代碼财饥。
???????? 3.[a?func]會被轉(zhuǎn)換為objc_msgSend(a,"someFunc")钥星,字面的意思也很容易理解,就是給a這個instance贯莺,發(fā)“someFunc”這個消息缕探,以selector的形式还蹲。在運行階段谜喊,執(zhí)行到上述的objc_msgSend這個函數(shù)時。
???? ?? 4.函數(shù)內(nèi)部會到a對應(yīng)的內(nèi)存地址山卦,尋找func這個方法的地址诵次,并執(zhí)行藻懒。
????? ? 5.如果找不到,就會拋一個“unknown selector sent to instance”的異常。
注意:(比如.h中聲明了方法鄙早,但.m中沒有實現(xiàn)椅亚,就可以重現(xiàn)這個錯誤)所以嚴格意義上來講,任何Objective C的函數(shù)調(diào)用呀舔,編譯階段的表現(xiàn),都只能算一種“發(fā)消息”的行為珠插。
*/
二颖对、為什么使用匯編語言
其實在objc-msg-x86_64.s中包含了多個版本的objc_msgSend方法缤底,它們是根據(jù)返回值的類型和調(diào)用者的類型分別處理的:
objc_msgSendSuper:向父類發(fā)消息,返回值類型為id
objc_msgSend_fpret:返回值類型為floating-point江解,其中包含objc_msgSend_fp2ret入口處理返回值類型為longdouble的情況
objc_msgSend_stret:返回值為結(jié)構(gòu)體
objc_msgSendSuper_stret:向父類發(fā)消息徙歼,返回值類型為結(jié)構(gòu)體
當需要發(fā)送消息時鲁沥,編譯器會生成中間代碼,根據(jù)情況分別調(diào)用objc_msgSend, objc_msgSend_stret, objc_msgSendSuper,或objc_msgSendSuper_stret其中之一彭谁。
這也是為什么objc_msgSend要用匯編語言而不是OC允扇、C或C++語言來實現(xiàn)考润,因為單獨一個方法定義滿足不了多種類型返回值,有的方法返回id唱矛,有的返回int井辜≈嘟牛考慮到不同類型參數(shù)返回值排列組合映射不同方法簽名(method signature)的問題刷允,那switch語句得老長了。
這些原因可以總結(jié)為Calling Convention,也就是說函數(shù)調(diào)用者與被調(diào)用者必須約定好參數(shù)與返回值在不同架構(gòu)處理器上的存取規(guī)則歧蒋,比如參數(shù)是以何種順序存儲在棧上州既,或是存儲在哪些寄存器上。
除此之外還有其他原因吴叶,比如其可變參數(shù)用匯編處理起來最方便阐虚,因為找到IMP地址后參數(shù)都在棧上。
要是用C++傳遞可變參數(shù)那就悲劇了蚌卤,prologue機制會弄亂地址(比如i386上為了存儲ebp向后移位4byte)实束,最后還要用epilogue打掃戰(zhàn)場。而且匯編程序執(zhí)行效率高逊彭,在Objective-CRuntime中調(diào)用頻率較高的函數(shù)好多都用匯編寫的咸灿。
謝謝!!