iOS開發之Runtime機制深入解析,ios開發runtime機制

來源:互聯網
上載者:User

iOS開發之Runtime機制深入解析,ios開發runtime機制

本篇主要講述在 OC 開發中主要涉及到的運行時機制:

運行時的工作:

 運行時在 OC 中的工作:OC 語言的設計模式決定了儘可能的把程式從編譯和連結時延遲到運行時。只要有可能,OC 總是使用動態方式來解決問題。這意味著 OC 語言不僅需要一個編譯器,同時也需要一個運行時系統來執行編譯好的代碼。這兒的運行時系統扮演的角色類似於 OC 語言的作業系統,OC 基於該系統來工作。

 

 運行時的簡單應用:

 OC 2.0運行時系統參考庫描述了OC 運行庫的資料結構和函數介面。程式可以通過這些介面來和 OC 運行時系統互動。例如:增加一個類或者方法,或者獲得所有類的定義列表等。

 

 運行時的兩個版本:

 OC 運行時系統有兩個版本,早期版本主要應用於 OC1.0中,現行版本用於 OC2.0中,在早期版本中,如果改變了類中執行個體變數的布局,就必須重新編譯該類的所有子類。在現行版本中,如果改變了類中執行個體變數的布局,無需重新編譯該類的任何子類。早起版本一般用於 Max OS X 系統中32位程式,此外可視為全部是現行版本。

 

 

 互動途徑:

    1、通過 OC 原始碼:

        當編譯 OC 類和方法時,編譯器為實現語句動態特性將自動建立一些資料結構和函數。運行時系統的主要功能就是根據原始碼中的運算式發送訊息。

 

    2、通過 Foundation 架構中類 NSObject 的方法:

        Cocoa 程式中絕大部分類都是 NSObject 類的子類,所以大部分都繼承了 NSObject 類的方法,因而繼承了 NSObject類的行為。然而某些情況下,NSObject 類僅僅定義了完成某件事情的模板,而沒有提供所有需要的代碼,某些 NSObject 的方法只是簡單的從運行時系統中獲得資訊,從而允許對象進行一定程度的自我檢查。如:class 返回對象的類:isKindOfClass:和 isMemberOfClass:則檢查對象是否在指定的類繼承體系中;respondsToSelector:檢查對象能夠相應指定的訊息;conformsToProtocol:檢查對象是否實現了指定協議類的方法;methodForSelector:則返回指定方法實現的地址。

    3、直接通過調用運行時系統的函數:

        運行時系統是一個公開介面的動態庫,由一些資料結構和函數的集合組成,這些資料結構和函數的聲明標頭檔在/usr/include/objc 中。這些函數支援用純 C 的函數來實現和 OC 同樣的功能。浪遊一些函數構成了 NSObject 類方法的基礎。這些函數使得訪問運行時系統介面和提供開發工具成為可能。儘管大部分情況下他們在 OC 程式中不是必須的,但是有時候對於 OC 這樣的程式來說某些函數是非常有用的。

 

 運行時的訊息機制:

    1、獲得方法地址:

        避免動態綁定的唯一方法就是取得方法的地址,並且直接像函數調用一樣調用它。當一個方法會被聯絡調用很多次,而且您希望節省每次調用方法都要發送訊息的開銷時,使用方法地址來調用方法就顯得很有效。

        利用 NSObject 類中的 methodForSelector:方法,可以獲得一個指向方法實現的指標,並可以使用該指標直接調用方法實現。methodForSelector:返回的指標和賦值的變數類型必須完全一致,包括方法的參數類型和傳回值類型都在類型識別的考慮範圍中。

        在指定的訊息被重複發送很多次時,避免動態綁定將減少大部分訊息的開銷。

 

    2、objc_msgSend 函數

        在 OC 中,訊息是直到啟動並執行時候才和方法實現綁定的,編譯器會把一個訊息運算式轉換成一個對訊息函數objc_msgSend 的調用。該函數有兩個主要參數:訊息接收者和訊息對應的方法名字(也就是方法的選標)。

        objc_msgSend(receiver, selector),同時接收訊息中的任意數目的參數:objc_msgSend(receiver, selector, arg1, arg2,...)

        該訊息函數做了動態綁定所需要的一切;找到對應的方法實現-->將訊息接收者對象和參數傳遞給找到的方法實現-->將方法實現的傳回值作為該函數的傳回值返回 

        

        當對象收到訊息時,訊息函數首先根據該對象的 isa 指標找到該對象所對應的類的方法表,並從表中尋找該訊息對應的方法選標,如果找不到,objc_msSend 將從父類中找,知道 NSObject 類。一旦找到了選標,objc_msgSend 則以訊息接收者對象為參數調用,調用該選標對應的方法實現。這就是在運行時系統中選擇方法實現的方式。在物件導向編程中一般稱作方法和訊息動態綁定的過程。

        為了加快訊息的處理過程,運行時系統通常會將使用過的方法選標和方法實現的地址放入緩衝中。每個類都有一個獨立的緩衝,同時包括繼承的方法和在該類中定義的方法。訊息函數會首先檢查訊息接收者對象對應的類的緩衝(理論上,如果一個方法被使用過一次,那麼它很可能被再次使用)。如果在緩衝中已經有了需要的方法選標,則訊息僅僅比函數調用慢一點點。如果程式運行了足夠長的時間,幾乎每個訊息都能在緩衝中找到方法實現。程式運行時,緩衝也將隨著新的訊息的增加而增加。

 

    3、使用隱藏的參數

        當 objc_msgSend 找到方法對應的實現時,它將直接調用該方法的實現,並將訊息中所有的參數都傳遞給方法實現,同時,還將傳遞兩個隱藏的參數:

            1、接受訊息的對象:可以通過 self 來引用訊息接收者對象

            2、方法選標:通過選標_cmd 來引用方法本身。

        儘管這些參數沒有被顯示聲明,但在原始碼中仍然可以引用它們。

 

 動態方法解析:

    1、動態方法解析:

        @dynamic property name; 表示編譯器需動態產生該屬性對應的方法。

        可以通過實現 resolveInstanceMethod:和 resolveClassMethod:來動態實現給定選標的對象方法或者類方法。

        OC 方法可以認為是至少有兩個參數 self 和_cmd 的 C 函數。可以通過 class_addMethod 方法將一個函數加入到類的方法中,如下:

         

         void dynamicMethodIMP(id self, SEL _cmd) {

            // implementation...

         }

         + (BOOL)resolveInstanceMethod:(SEL)sel {

             if (sel == @selector(resolveThisMethodDynamically)) {

             class_addMethod([self class], sel, (IMP) dynamicMethodIMP, "v@:");

             return YES;

         }

             return [super resolveInstanceMethod:sel];

         }

 

        在進入訊息轉寄機制之前,respondsToSelector:和 instancesRespondToSelector:會被首先調用。可以在這兩個方法中為傳進來的選標提供一個 IMP。如果您實現了 resolveInstanceMethod:方法但是仍然希望正常的訊息轉寄機制進行,只需要返回 NO 就可以了。

 

    2、動態載入

        OC 程式可以在運行時連結和載入新的類和範疇類。新載入的類和在程式啟動時載入的類並沒有區別。

        動態載入可以用在很多地方,例如,系統配置中的模組就是被動態載入的。

 

        應用情境:

            在 Cocoa 環境中,動態載入一般被用來對應用程式進行定製。可以在運行時載入其他程式員編寫的模組(和 interface Build載入定製的調色盤以及系統配置程式載入定製的模組類似)。這些模組通過許可的方式擴充了自身的程式,而無需自己來定義或者實現。自己提供了架構,二其他程式員提供了實現。

 

 訊息轉寄:

     1、訊息轉寄

        如果一個對象收到一條無法處理的訊息,運行時系統會在拋出錯誤前,給該對象發送一條 forwardInvocation:訊息,該訊息的唯一參數是個 NSInvocation 類型的對象,該對象封裝了原始的訊息和訊息的參數。所以可以實現 forwardInvocation: 方法來對不能處理的訊息做一些預設的處理,也可以以其它的某種方式來避免錯誤被拋出。

        當一個對象沒有響應的方法實現而無法響應某訊息時,運行時系統將通過 forwardInvocation: 訊息通知該對象。每個對象都從 NSObject 類中整合了 forwardInvocation: 方法。然而,NSObject 中的方法實現只是簡單的調用了 doerNotRecognizeSelector:。 通過實現自己的 forwardInvocation: 方法可以在該方法實現中將訊息轉寄給其他對象。

        訊息可以通過 invokeWithTarget:方法來轉寄:

        

         - (void)forwardInvocation:(NSInvocation *)anInvocation {

             if ([someOtherObject respondsToSelector:[anInvocation selector]])

                 [anInvocation invokeWithTarget:someOtherObject];

             else

                 [super forwardInvocation:anInvocation];

         }

     

        forwardInvocation:方法就像一個不能識別的訊息的分發中心,將這些訊息轉寄給不同接收對象。它可以將一個訊息翻譯成另外一個訊息,或者簡單的“吃掉”某些訊息,因此沒有響應也沒有錯誤。forwardInvocation:方法也可以對不同的訊息提供同樣的相應,這一切都取決於方法的具體實現。該方法所提供是將不通的對象連結到訊息鏈的能力。

     

        注意:forwardInvocation:方法只有在訊息接受對象中無法正常響應訊息時才會被調用。所以,如果您希望您的對象將 clickBtn:訊息轉寄給其他對象,您的對象不能有 clickBtn:方法。否則,forwardInvocation:將不可能會被調用。

     

     2、訊息轉寄和多重繼承

        訊息轉寄很像整合,並且可以用來在 OC 程式中類比多重繼承。一個對象通過轉寄來響應訊息,看起來就像該對象從別的類那裡借來了或者“繼承”了方法實現一樣。通過 forwardInvocation: 方法將一個類中的訊息轉寄給另一個類.

     3、訊息代理對象

     4、訊息轉寄和類繼承

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.