IOS -運行時 (訊息傳遞再探究)

來源:互聯網
上載者:User

一 訊息尋找最佳化
至此,我們已經明白了Objective-c中大致的訊息傳遞過程,我們發現如果每次函數調用都經曆上面的過程(,那函數調用的效率就會很低,尤其是當類的繼承層次很多的時候,它需要一層層的尋找其效率將會更低,為了加快尋找調用的速度,Objective-c對訊息尋找做了最佳化。
從前一節的類對象我們知道它含有一個 struct objc_cache *cache成員,這個緩衝就是為了提高尋找的效率的。每個類都有自己的緩衝,同時包括繼承的方法和在該類中定義的方法。當我們在尋找IMP 時:

     1.首先去該類的方法 cache 中尋找,如果找到了就返回它
     2.如果沒有找到,就去該類的方法列表中尋找。如果在該類的方法列表中找到了,則將 IMP 返回,並將它加入cache中緩衝起來。根據最近使用原則,這個方法再次調用的可能性很大,緩衝起來可以節省下次調用再次尋找的開銷。
     3.如果在該類的方法列表中沒找到對應的 IMP,在通過該類結構中的 super_class指標在其父類結構的方法列表中去尋找,直到在某個父類的方法列表中找到對應的IMP,返回它,並加入cache中。
     4.如果在自身以及所有父類的方法列表中都沒有找到對應的 IMP,則進入下文中要講的訊息轉寄流程。

二 訊息轉寄      給一個對象發送它不能處理的訊息會得到出錯提示,然而,Objective-C運行時系統在拋出錯誤之前,會給訊息接收對象發送一條特別的訊息forwardInvocation 來通知該對象,該訊息的唯一參數是個NSInvocation類型的對象——該對象封裝了原始的訊息和訊息的參數。
我們可以實現forwardInvocation:方法來對不能處理的訊息做一些預設的處理,也可以將訊息轉寄給其他對象來處理,而不拋出錯誤。
       關於訊息轉寄的作用,可以考慮如下情景:假設,我們需要設計一個能夠響應negotiate訊息的對象,並且能夠包括其它類型的對象對訊息的響應。 通過在negotiate方法的實現中將negotiate訊息轉寄給其它的對象來很容易的達到這一目的。      更進一步,假設我們希望我們的對象和另外一個類的對象對negotiate的訊息的響應完全一致。一種可能的方式就是讓我們的類繼承其它類的方法實現。 然而,有時候這種方式不可行,因為我們的類和其它類可能需要在不同的繼承體系中響應negotiate訊息。       雖然我們的類無法繼承其它類的negotiate方法,但我們仍然可以提供一個方法實現,這個方法實現只是簡單的將negotiate訊息轉寄給其他類的對象,就好像從其它類那兒“借”來的現一樣。如下所示:- negotiate  {    if ([someOtherObject respondsToSelector:@selector(negotiate)])        return  [someOtherObject negotiate];
    return self;}
      這種方式顯得有欠靈活,特別是有很多訊息都希望傳遞給其它對象時,我們就必須為每一種訊息提供方法實現。此外,這種方式不能處理未知的訊息。當我們寫下代碼時,所有我們需要轉寄的訊息的集合都必須確定。然而,實際上,這個集合會隨著運行時事件的發生,新方法或者新類的定義而變化。     forwardInvocation:訊息給這個問題提供了一個更特別的,動態解決方案:當一個對象由於沒有相應的方法實現而無法響應某訊息時,運行時系統將通過forwardInvocation:訊息通知該對象。每個對象都從NSObject類中繼承了forwardInvocation:方法。然而,NSObject中的方法實現只是簡單地調用了doesNotRecognizeSelector:。通過實現我們自己的forwardInvocation:方法,我們可以在該方法實現中將訊息轉寄給其它對象。 要轉寄訊息給其它對象,forwardInvocation:方法所必須做的有:     1.決定將訊息轉寄給誰,並且     2.將訊息和原來的參數一塊轉寄出去訊息可以通過invokeWithTarget:方法來轉寄:- (void) forwardInvocation:(NSInvocation *)anInvocation{    if ([someOtherObject respondsToSelector:[anInvocation selector]])        [anInvocation invokeWithTarget:someOtherObject];    else        [super forwardInvocation:anInvocation];} 
     轉寄訊息後的返回值將返回給原來的訊息寄件者。您可以將返回任何類型的返回值,包括: id,結構體,浮點數等。       forwardInvocation:方法就像一個不能識別的訊息的分發中心,將這些訊息轉寄給不同接收對象。或者它也可以象一個運輸站將所有的訊息都發送給同一個接收對象。它可以將一個訊息翻譯成另外一個訊息,或者簡單的"吃掉“某些訊息,因此沒有響應也沒有錯誤。forwardInvocation:方法也可以對不同的訊息提供同樣的響應,這一切都取決於方法的具體實現。該方法所提供是將不同的對象連結到訊息鏈的能力。
注意: forwardInvocation:方法只有在訊息接收對象中無法正常響應訊息時才會被調用。 所以,如果我們希望一個對象將negotiate訊息轉寄給其它對象,則這個對象不能有negotiate方法。否則,forwardInvocation:將不可能會被調用。

三 小結        現在當我們回過頭來在看http://blog.csdn.net/zhangzhebjut/article/details/24134863中的執行個體應該明白了IOS中整個函數的調用流程。IOS的運行時還是挺強大的,通過對運行時的學習,對Objective-c類型系統有一個更加深刻的瞭解。         其實如果熟悉Python的人應該也知道,Python是一個全動態語言,它的類型系統和Objective-c有些相像,有時間給我會將其與Objective-c做一個詳細的對照。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.