runtime淺談(一)動態運行時和消息機制

最近聽周圍的朋友在討論runtime,索性來研究一下,runtime是什麼,原理又是什麼。

總的來講,runtime簡稱運行時,就是系統在運行的時候的一些機制,它是開源的。其中最關鍵的就是消息機制。

1、Objective-C 的 Runtime 是一個運行時庫(Runtime Library),它是一個主要使用 C 和彙編寫的庫,爲 C 添加了面相對象的能力並創造了 Objective-C這就是說它在類信息(Class information) 中被加載,完成所有的方法分發,方法轉發,等等.然而對於C語言,函數的調用在編譯的時候就會決定調用哪個函數。編譯完成之後直接順序執行。

2、Objective-C runtime 創建了所有需要的結構體,讓 Objective-C 的面相對象編程變爲可能。

3、Objective -C的函數調用爲消息發送。屬於動態調用過程。在編譯的時候並不能決定真正調用哪個函數,消息只有到運行時纔會和函數實現綁定起來,而不是按照編譯好的邏輯一成不變的執行,這也是有可能造成程序崩潰的原因。

4、運行時系統通過Objective-C源碼、NSObject方法和運行時系統的函數與runtime system進行交互。

本次我們只討論有關消息的問題:

消息例子:
<span style="font-size:14px;">[obj makeText];</span>
其中obj是一個對象,makeText是一個函數名稱。對於這樣一個簡單的調用。在編譯時RunTime會將上述代碼轉化成
<span style="font-size:14px;">objc_msgSend(obj,@selector(makeText));</span>
iOS中的obj都繼承於NSObject。
<span style="font-size:14px;">@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}</span>
在NSObjcet中存在一個Class的isa指針。然後我們看看Class:
typedef struct objc_class *Class;
struct objc_class {
  Class isa; // 指向metaclass 
  Class super_class ; // 指向其父類
  const char *name ; // 類名
  long version ; // 類的版本信息,初始化默認爲0,可以通過runtime函數class_setVersion和class_getVersion進行修改、讀取
  long info; // 一些標識信息,如CLS_CLASS (0x1L) 表示該類爲普通 class ,其中包含對象方法和成員變量;CLS_META (0x2L) 表示該類爲 metaclass,其中包含類方法;
  long instance_size ; // 該類的實例變量大小(包括從父類繼承下來的實例變量);
  struct objc_ivar_list *ivars; // 用於存儲每個成員變量的地址
  struct objc_method_list **methodLists ; // 與 info 的一些標誌位有關,如CLS_CLASS (0x1L),則存儲對象方法,如CLS_META (0x2L),則存儲類方法;
  struct objc_cache *cache; // 指向最近使用的方法的指針,用於提升效率;
  struct objc_protocol_list *protocols; // 存儲該類遵守的協議
    }

Class isa:指向metaclass,也就是靜態的Class。一般一個Obj對象中的isa會指向普通的Class,這個Class中存儲普通成員變量和對 象方法(“-”開頭的方法),
普通Class中的isa指針指向靜態Class,靜態Class中存儲static類型成員變量和類方法(“+”開頭的方 法)。

@selector (makeText):這是一個SEL方法選擇器。SEL其主要作用是快速的通過方法名字(makeText)查找到對應方法的函數指針,然後調用其函 數。SEL其本身是
一個Int類型的一個地址,地址中存放着方法的名字。對於一個類中。每一個方法對應着一個SEL。所以iOS類中不能存在2個名稱相同 的方法,即使參數類型不同,因爲
SEL是根據方法名字生成的,相同的方法名稱只能對應一個SEL。

最後來看看具體消息發送之後是怎麼來動態查找對應的方法的。

首先,編譯器將代碼[obj makeText];轉化爲objc_msgSend(obj, @selector (makeText));,在objc_msgSend函數中。首先通過obj的isa指針找到obj對應的class。在Class中先去cache中 通過SEL查找對應函數method(猜測cache中method列表是以SEL爲key通過hash表來存儲的,這樣能提高函數查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,則取superClass中查找。若能找到,則將method加 入到cache中,以方便下次查找,並通過method中的函數指針跳轉到對應的函數中去執行。


方法調用中的隱藏參數:

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

1、接收消息的對象(也就是self指向的內容)

2、方法選標(_cmd指向的內容)


相關鏈接:

http://www.cocoachina.com/ios/20141018/9960.html

http://my.oschina.net/panyong/blog/298631

http://blog.csdn.net/wzzvictory/article/details/8624057


發佈了24 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章