Objecive-C語言中RunTime機制

為了充分介紹Objecive-C語言中RunTime機制复罐,使讀者對RunTime機制有一個清晰的了解。本文將從以下幾個部分來介紹相關(guān)知識:

  • 第一部分將介紹Objecive-C語言的基本特性善绎。
  • 第二部分將介紹Objecive-C類對象與isa指針的本質(zhì)。
  • 第三部分將介紹RunTime整個流程。
  • 第四部分將介紹RunTime的常見應(yīng)用場合。

第一部 Objecive-C語言基本特性

Objecive-C(以下簡稱OC)是一種采用消息結(jié)構(gòu)阔逼、面向運行時、動態(tài)的面向?qū)ο蟮恼Z言地沮。其運行時所執(zhí)行的代碼由運行環(huán)境來決定嗜浮。它本質(zhì)上是C的超集。
OC中重要的工作由“運行期組建”(runtime component)而非編譯器完成摩疑。

備注:一般來說面向?qū)ο蟮恼Z言有兩種實現(xiàn)形式:一種是消息結(jié)構(gòu)危融,另一種是采用函數(shù)調(diào)用。它們兩者的區(qū)別在于雷袋。后者運行時所執(zhí)行的代碼由編譯器決定吉殃,也就是說采用函數(shù)調(diào)用的語言在編譯期編譯器就會查找出運行是代碼所執(zhí)行的方法。采用消息結(jié)構(gòu)(Objecive-C)語言只有在運行時確定所執(zhí)行的代碼方法楷怒。

第二部 Objecive-C中對象與isa指針蛋勺。

“對象”是面向?qū)ο笳Z言的基本構(gòu)造單元,開發(fā)者可以通過對象來存儲和傳遞數(shù)據(jù)鸠删。理解“對象”對于理解消息傳遞機制有著重要的意義抱完。

要認識什么是isa指針,我們得先明確一點:
在OC中刃泡,任何類的定義都是對象巧娱。類和類的實例(對象)沒有任何本質(zhì)上的區(qū)別碉怔。任何對象都有isa指針。

描述OC對象所用的數(shù)據(jù)類型定義在運行期程序文件的頭文件里:

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;};
    typedef struct objc_object *id;```
由此可見每個對象的首個成員時Class類的變量禁添,該對象稱為isa指針眨层。它指向?qū)ο蟮念悺?
類的定義也在頭文件里:

@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}```
看出來NSObject定義了一個成員變量,我們繼續(xù)尋找:

typedef struct objc_class *Class;
/// Represents an instance of a class.

Class 是一個 objc_class 結(jié)構(gòu)類型的指針, id是一個 objc_object 結(jié)構(gòu)類型的指針上荡。

繼續(xù)打開objc_class,我們找到class的定義:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                                        &OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;```

從上可以看出:isa本質(zhì)上是一個Class 類型的指針趴樱。每個實例對象有個isa的指針,他指向?qū)ο蟮念悺6鳦lass里也有個isa的指針, 指向meteClass(元類)酪捡。元類保存了類方法的列表叁征。當類方法被調(diào)用時,先會從元類查找類方法的實現(xiàn)逛薇,如果沒有捺疼,元類會向他父類查找該方法。同時注意的是:元類(meteClass)也是類永罚,它也是對象啤呼。元類也有isa指針,它的isa指針最終指向的是一個根元類(root meteClass).根元類的isa指針指向本身,這樣形成了一個封閉的內(nèi)循環(huán)呢袱。

下面這張圖很好的解釋了類的繼承關(guān)系:
![449095-3e972ec16703c54d.png](http://upload-images.jianshu.io/upload_images/449095-b5ed6ceedfbc2b39.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

每一個對象本質(zhì)上都是一個類的實例官扣。其中類定義了成員變量和成員方法的列表。對象通過對象的isa指針指向類羞福。

每一個類本質(zhì)上都是一個對象惕蹄,類其實是元類(meteClass)的實例。元類定義了類方法的列表治专。類通過類的isa指針指向元類卖陵。

所有的元類最終繼承一個根元類,根元類isa指針指向本身张峰,形成一個封閉的內(nèi)循環(huán)泪蔫。

####第三部分:RunTime機制
RunTime指一個程序在運行(或者在被執(zhí)行)的環(huán)境。簡稱運行時喘批。它指的是系統(tǒng)在運行的時候的一些機制撩荣,其中最主要的是消息機制。

OC中RunTime本質(zhì)上是一套比較底層的純C語言API, 屬于1個C語言庫, 包含了很多底層的C語言API谤祖。 在我們平時編寫的OC代碼中, 程序運行過程時, 其實最終都是轉(zhuǎn)成了runtime的C語言代碼婿滓。RunTime提供了一些使得對象之間能夠傳遞消息的重要函數(shù)老速,并且包含了創(chuàng)建類實例所用的全部邏輯粥喜。

#####基礎(chǔ)知識:
在OC中,給某個對象傳遞消息可以這樣寫:
 `    id returnValue = [obj messageName:parameter];`
其中obj是接受對象,messageName是選擇子(selector),parameter是參數(shù)橘券。
我們把selector和parameter結(jié)合起來稱為消息额湘。

編譯器會把以上消息轉(zhuǎn)化為C語言函數(shù)調(diào)用:
`id returnValue = objc_msgSend(id obj,SEL messageName,parameter).`
`objc_msgSend`是消息傳遞機制中核心函數(shù)卿吐。其原型如下:
` void  objc_msgSend(id self,SEL cmd,...).`

消息傳遞機制主要分為以下幾個階段:
#####第一階段:消息傳遞機制(pass a message)
編譯把OC中方法轉(zhuǎn)化objc_msgSend形式后。objc_msgSend函數(shù)首先通過接受對象(obj)的isa指針找到接收對象(obj)對應(yīng)的類(class)锋华。在類(Class)中先去cache中 通過選擇子(SEL)查找對應(yīng)函數(shù)的方法method()嗡官,若 cache中未找到。再去方法列表(methodList)中查找毯焕,若方法列表(methodList)中未找到衍腥,則去superClass中查找。若能找到纳猫,則將method加 入到cache中婆咸,以方便下次查找,并通過method中的函數(shù)指針跳轉(zhuǎn)到對應(yīng)的函數(shù)中去執(zhí)行芜辕。若沒有找到尚骄,消息傳遞機制將進入第二階段消息轉(zhuǎn)發(fā)階段(消息轉(zhuǎn)發(fā)機制)。

緩存:每一個類都都有一塊緩存(cache)侵续。其存儲的是“快速映射表”倔丈。objc_msgSend會將方法的匹配結(jié)果緩存在快速映射表中。

消息派發(fā)系統(tǒng)會將類的方法列表的名稱映射到相關(guān)方法的實現(xiàn)上状蜗。以此來找到應(yīng)該調(diào)用的方法需五。這些方法均以函數(shù)指針(IMP)的形式來表示。其原型是:
`id(*IMP)(id轧坎,SEL警儒,...)`

方法調(diào)配技術(shù):運行此特性可以改變相關(guān)方法的實現(xiàn)。
NSString 有可以響應(yīng)以下幾個方法:
![417684A6-0D92-4EE3-961C-B16FFE6D5ED8.png](http://upload-images.jianshu.io/upload_images/449095-9843bfca776f234e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
OC運行系統(tǒng)提供了幾個方法能夠操控這張表眶根。開發(fā)者可以向其中新增選擇子,也可以改變選擇子的實現(xiàn)蜀铲,還可以交換選擇子所映射的指針。經(jīng)過幾次操作可以變成以下:
![0D1876D1-7098-42E2-B4B3-08AF769CE77F.png](http://upload-images.jianshu.io/upload_images/449095-840df668989dc4ad.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
對比兩張表属百,我們可以發(fā)現(xiàn)下面新增加了一個選擇子记劝。交換兩個選擇子的實現(xiàn)∽迦牛可以看出方法調(diào)配技術(shù)的強大之處厌丑。

交換兩個方法的實現(xiàn),參數(shù)為方法的實現(xiàn)渔呵。
`void method_exchangeImplementations(Method m1,Method m2)`

得到方法的實現(xiàn):
 `  Method class_getInstanceMethod(Class aClsaa,SEL aSelector)`

實際應(yīng)用中交換兩個方法的實現(xiàn)意義不大怒竿。一般是在類別中新增加一個方法,然后交換兩個方法的實現(xiàn)扩氢。以此來改變類的方法的實現(xiàn)耕驰。
![消息傳遞](http://upload-images.jianshu.io/upload_images/449095-fca5ec800efe1bb9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#####第二階段:消息轉(zhuǎn)發(fā)機制(message forwarding)
消息轉(zhuǎn)發(fā)機制分為兩個階段:
######1.動態(tài)方法解析:
第一階段運行系統(tǒng)會先征詢接受者所屬的類看其是否動態(tài)添加方法以處理當前的這個未知選擇子(SEL)。
在對象收到無法解讀的消息后录豺,便會調(diào)用所屬類的下列方法:
`+(BOOL)resolveInstanceMethod:(SEL)selector`
該方法參數(shù)就是需要處理的未知選擇子朦肘。返回值是表示這個類是否能新增一個方法處理這個未知選擇子饭弓。在處罰完整消息轉(zhuǎn)發(fā)機制前本類有機會增加一個方法處理這個未知選擇子。在此類方法中可以通過`class_addMethod` 增加一個方法處理未知選擇子媒抠。
如果是類方法將會觸發(fā)下面這個方法:
`+(BOOL)resolveClassMethod:(SEL)selector`

######2.完整的消息轉(zhuǎn)發(fā)機制:
如果第一階段沒有成功的處理未知選擇子弟断,那么接受者自己再也沒有辦法動態(tài)的添加方法來響應(yīng)該未知選擇子的消息了 。此時運行系統(tǒng)會啟動完整的消息轉(zhuǎn)發(fā)機制趴生。這里又分為兩個小階段:

**第一階段**:會請接受者看看有沒有其他對象能處理這條消息阀趴。若有,運行系統(tǒng)會把消息轉(zhuǎn)給那個對象(備援的接受者),消息轉(zhuǎn)發(fā)結(jié)束 苍匆。若沒有將進入第二階段舍咖。
`-(id)forwardingTargetForSelector:(SEL)selector`
在此方法中若當前接受者能找到備援對象,那將其返回锉桑。若找不到返回nil排霉,觸發(fā)下一個階段。

**第二階段**:運行系統(tǒng)會把消息的全部細節(jié)封裝到NSInvocation對象中民轴,再給接受者一次機會攻柠,另其解決當前未知選擇子(SEL)。
   
如果消息轉(zhuǎn)發(fā)到了這一個階段后裸,運行系統(tǒng)就會啟用完整的消息轉(zhuǎn)發(fā)機制瑰钮。首先創(chuàng)建NSInvocation對象。把消息的全部細節(jié)封裝于其中微驶。此對象包括選擇子浪谴,目標對象和參數(shù)。觸發(fā)NSInvocation對象時因苹,消息派發(fā)系統(tǒng)(message-dispathch-system)將親自把消息指派給目標對象苟耻。

此步驟運行系統(tǒng)會調(diào)用下面方法來處理:
` -(void)forwardingInvocation:(NSInvocation)invocation。`
這個方法可以有多種實現(xiàn)形式扶檐⌒渍龋可以很簡單,改變消息的調(diào)用目標款筑,使消息在新的目標上調(diào)用智蝠。這個備援接受者是相同的原理∧问幔可以為改變消息的內(nèi)容杈湾,參數(shù)。使其可以被目標對象接受攘须。也可以更換選擇子等漆撞。

消息轉(zhuǎn)發(fā)全流程:
![消息轉(zhuǎn)發(fā)全流程](http://upload-images.jianshu.io/upload_images/449095-402f05427a489f4c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
####第四部分:RunTim的常見應(yīng)用場合
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叫挟,更是在濱河造成了極大的恐慌艰匙,老刑警劉巖限煞,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抹恳,死亡現(xiàn)場離奇詭異,居然都是意外死亡署驻,警方通過查閱死者的電腦和手機奋献,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旺上,“玉大人瓶蚂,你說我怎么就攤上這事⌒ǎ” “怎么了窃这?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長征候。 經(jīng)常有香客問我杭攻,道長,這世上最難降的妖魔是什么疤坝? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任兆解,我火速辦了婚禮,結(jié)果婚禮上跑揉,老公的妹妹穿的比我還像新娘锅睛。我一直安慰自己,他們只是感情好历谍,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布现拒。 她就那樣靜靜地躺著,像睡著了一般望侈。 火紅的嫁衣襯著肌膚如雪具练。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天甜无,我揣著相機與錄音扛点,去河邊找鬼。 笑死岂丘,一個胖子當著我的面吹牛陵究,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奥帘,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼铜邮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起松蒜,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤扔茅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秸苗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體召娜,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年惊楼,在試婚紗的時候發(fā)現(xiàn)自己被綠了玖瘸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡檀咙,死狀恐怖雅倒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弧可,我是刑警寧澤蔑匣,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站棕诵,受9級特大地震影響裁良,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜年鸳,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一趴久、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧搔确,春花似錦彼棍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涕蜂,卻和暖如春华匾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背机隙。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工蜘拉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人有鹿。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓旭旭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親葱跋。 傳聞我的和親對象是個殘疾皇子持寄,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容