IOS OC objc_msgSend的做用

一 消息傳遞


    OC中調用方法也叫消息傳遞(pass a message),消息有名稱(name) 或 選擇子(selector),能夠接受參數,並且能夠設定返回值。緩存


    OC中向某對象傳遞消息,會使用動態綁定機制來決定須要調用的方法,在底層,全部方法都是普通的C語言函數,然而對象受到信息以後,究竟調用什麼方法則徹底完成於運行期決定,甚至可用在程序運行時改變,這些特性使得OC爲動態語言。給對象發送消息的寫法:架構

id returnValue = [object messageName:parameter];

    returnValue     是 返回值函數

    object             是 接受者(receiver)
優化

    messageName 是 選擇子(selector)spa

    選擇子與參數合起來稱爲消息。指針


     編譯器看到 [object messageName:parameter] 消息後會轉換爲標準的C語言函數調用,所調用函數是消息傳遞機制中的核心函數,objc_msgSend,其原型以下:code

void objc_msgSend(id self,SEL cmd, …);

    這是個「參數個數可變的函數」,能接受多個參數,第一個參數表明 接受者,第二參數表明選擇子(SEL 就是選擇子的類型,選擇子就是方法名),後續參數就是消息中的那些參數,其順序不變。
對象




二消息調用過程


編譯器會把剛纔例子中的消息轉換成如下函數繼承

id = returnValue = objc_msgSend(someObject,@selector(messageName:),parameter);

    objc_msgSend 函數會依據接受者與選擇子的類型來調用適當的方法,爲了完成此操做,該方法須要在接受者所屬的類中搜尋其「方法列表」,若是能找到與選擇子名稱相符的方法,就跳至其實現代碼。如果找不到,那就沿着繼承體系繼續向上查找,等找適合的方法以後再跳轉,若是最終仍是找不到相符的方法,那就執行「消息轉發」操做(下篇講),調用一個方法須要不少步驟,爲了簡化開銷,objc_msgSend會將匹配結果緩存在「快速映射表」裏面,每一個類都有這樣一塊緩存,在稍後向該類發送選擇子相同的消息,執行效率會很快。cmd




三 非objc_message 狀況

    objc_msgSend_stret  若是待發送的消息要返回結構體,由該函數處理。只有當CPU寄存器可以容納下返回類型時,該函數纔會處理。若是不能容納,則由另外一個函數執行派發

    objc_msgSend_fpret 若是返回的浮點數,由該函數處理,在某些架構的CPU中調用函數,須要堆「浮點數寄存器」作特殊處理。

    objc_msgSendSuper 若是要給超類發消息,例如[super message:parameter],由該函數處理。




四 尾調用優化

    上面提到objc_msgSend 等函數找到調用方法實現後,會「跳轉過去」,之因此能這樣作,是由於OC 對象的每一個方法均可以視爲簡單的C函數,原型以下

<return_type> Class_selector(id self,SEL _cmd,…)

    每一個類裏都有一張表格,其中的指針會指向這種函數,二選擇子的名稱則是查表時所用的「鍵」。ojbc_msgSend 等函數正是經過該表來尋求應該執行的方法並跳轉到實現。上面的原型和objc_msgSend 函數很像,是位了利用「尾調用優化」技術,令「跳轉到方法實現」操做變得更簡單。

    若是函數的最後操做是調用另外一個函數,就會運用到「尾調用優化」,編譯器會生成調轉至另外一個函數所需的字節碼,並且不會像調用堆棧中推入新的「棧幀」,只有當函數最後一個操做是調用其餘函數而不會將其返回值另做他用時,才能執行「尾調用優化」,改技術避免了過早發生」棧溢出」現象




五 總結

  •     消息由接受者,選擇子以及參數構成,給某個對象發送消息,也就至關於在該對象上 調用方法。

  •     發給某對象的所有消息都須要由 動態消息派發系統 來處理,該系統會查出對應的方法,並執行其代碼。


詳細請查閱《Effective Objective-c 2.0》

相關文章
相關標籤/搜索