iOS開發之Runtime機制深入解析

来源:http://www.cnblogs.com/Jepson1218/archive/2016/03/26/5324289.html
-Advertisement-
Play Games

本篇主要講述在 OC 開發中主要涉及到的運行時機制: 運行時的工作: 運行時在 OC 中的工作:OC 語言的設計模式決定了儘可能的把程式從編譯和鏈接時推遲到運行時。只要有可能,OC 總是使用動態的方式來解決問題。這意味著 OC 語言不僅需要一個編譯器,同時也需要一個運行時系統來執行編譯好的代碼。這兒 ...


本篇主要講述在 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、消息轉發和類繼承


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、概述 Xfermode全名transfer-mode,其作用是實現兩張圖疊加時的混合效果。 網上流傳的關於Xfermode最出名的圖來源於AndroidSDK的samples中,名叫Xfermodes.java,效果如下: [轉載請保留本文地址:http://www.cnblogs.com/go ...
  • 工具類 Activity ...
  • 這是深入淺出React Native教程的第二篇文章。 1. 環境配置 React Native環境配好之後,就可以開始創建我們的第一個App啦。 打開控制台,輸入 上述命令的作用是在當前文件夾下創建一個名字叫AwesomeProject的項目模板。在運行該命令之前,可以先用cd命令到自己想創建re ...
  • 一首先下載Jar包 https://github.com/square/okhttp 如果使用android studio只需要加入依賴 二--下載一張圖片並顯示 使用的是hanlder的方式 也可以把網路請求寫為一個工具類, get方式 ...
  • 展示效果如下: 大家可以看到這個界面很簡單,其實就是UITableView的佈局, 但是難點是在於如何從網上下載這些圖片,下載之後應如何進行存儲! 我們一步一步進行解析,先從單線程(主線程)進行多圖片下載 我們佈局上的文字及圖片的地址從plist文件中進行讀取 根據結構,我們自定義一個數據模型文件 ...
  • 今天在寫項目的時候,遇到了一件令人抓狂的事情。 正如標題所示,被這個方法弄的團團轉。 -(void)scrollViewDidEndScrollingAnimation:是協議里的方法。 意味當動畫結束時調用。 動畫?為什麼會有動畫呢? setContentOffset: animated: -這一 ...
  • 該教程主要介紹如何用react native來開發iOS,所以首先,你需要有一臺mac,當然黑蘋果也是可以的~ 創建一個react native的項目只需要安裝以下五個組件~~(但....坑爹的是,不翻牆的話安裝慢成狗呀) 1. 安裝 xcode 做過ios相關開發的都知道這個,作為ios開發的首席 ...
  • 廣播的概念 現實中:我們常常使用電臺通過發送廣播發佈消息,買個收音機,就能收聽 Android:系統在產生某個事件時發送廣播,應用程式使用廣播接收者接收這個廣播,就知道系統產生了什麼事件。Android系統在運行的過程中,會產生很多事件,比如開機、電量改變、收發簡訊、撥打電話、屏幕解鎖 廣播接收者的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...