iOS開發(fā)Runtime的理解與應(yīng)用

一、Runtime概念

  • RunTime簡稱運(yùn)行時(shí),其中最主要的是消息機(jī)制。

  • 對于C語言竭贩,函數(shù)的調(diào)用在編譯的時(shí)候會決定調(diào)用哪個(gè)函數(shù),編譯完成之后直接順序執(zhí)行莺禁,無任何二義性留量。

  • OC的函數(shù)調(diào)用成為消息發(fā)送,屬于動態(tài)調(diào)用過程。在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù)(事實(shí)證明楼熄,在編譯階段忆绰,OC可以調(diào)用任何函數(shù),即使這個(gè)函數(shù)并未實(shí)現(xiàn)可岂,只要聲明過就不會報(bào)錯(cuò)错敢。而C語言在編譯階段就會報(bào)錯(cuò))。

  • 只有在真正運(yùn)行的時(shí)候才會根據(jù)函數(shù)的名稱找到對應(yīng)的函數(shù)來調(diào)用缕粹。

    其動態(tài)性體現(xiàn)在三個(gè)方面:

1.動態(tài)類型:
即運(yùn)行時(shí)再決定對象的類型稚茅。簡單說就是id類型,任何對象都可以被id指針?biāo)钙秸叮挥性谶\(yùn)行時(shí)才能決定是什么類型亚享。像內(nèi)置的明確的基本類型都屬于靜態(tài)類型(int、NSString等)绘面。靜態(tài)類型在編譯的時(shí)候就能被識別出來欺税。所以,若程序發(fā)生了類型不對應(yīng)飒货,編譯器就會發(fā)出警告魄衅。而動態(tài)類型就編譯器編譯的時(shí)候是不能被識別的,要等到運(yùn)行時(shí)(run time)塘辅,即程序運(yùn)行的時(shí)候才會根據(jù)語境來識別晃虫。所以這里面就有兩個(gè)概念要分清:編譯時(shí)跟運(yùn)行時(shí)。
2.動態(tài)綁定:
基于動態(tài)類型扣墩,在某個(gè)實(shí)例對象被確定后哲银,其類型便被確定了。該對象對應(yīng)的屬性和響應(yīng)的消息也被完全確定呻惕,這就是動態(tài)綁定荆责。比如我們一般向一個(gè)NSObject對象發(fā)送-respondsToSelector:或者 -instancesRespondToSelector:等來確定對象是否可以對某個(gè)SEL做出響應(yīng),而在OC消息轉(zhuǎn)發(fā)機(jī)制被觸發(fā)之前亚脆,對應(yīng)的類 的+resolveClassMethod:和+resolveInstanceMethod:將會被調(diào)用做院,在此時(shí)有機(jī)會動態(tài)地向類或者實(shí)例添加新的方 法,也即類的實(shí)現(xiàn)是可以動態(tài)綁定的濒持;isKindOfClass也是一樣的道理键耕。
3.動態(tài)加載:
所謂動態(tài)加載就是我們做開發(fā)的時(shí)候icon圖片的時(shí)候在Retina設(shè)備上要多添加一個(gè)張@2x的圖片,當(dāng)設(shè)備更換的時(shí)候,圖片也會自動的替換。

二柑营、Runtime數(shù)據(jù)結(jié)構(gòu)

1.Class

Objective-C類是由Class類型來表示,Class 其實(shí)是指向 objc_class 結(jié)構(gòu)體的指針

typedef struct objc_class *Class;

我們可以從<objc/runtime.h>里面看到類的定義

struct object_class{
    Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
     Class super_class                        OBJC2_UNAVAILABLE;  // 父類
     const char *name                         OBJC2_UNAVAILABLE;  // 類名
     long version                             OBJC2_UNAVAILABLE;  // 類的版本信息屈雄,默認(rèn)為0
     long info                                OBJC2_UNAVAILABLE;  // 類信息,供運(yùn)行期使用的一些位標(biāo)識
     long instance_size                       OBJC2_UNAVAILABLE;  // 該類的實(shí)例變量大小
     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;  // 協(xié)議鏈表
#endif
}OBJC2_UNAVAILABLE;
2.id

id 是一個(gè)結(jié)構(gòu)體指針類型官套,它可以指向 Objective-C 中的任何對象酒奶。從<objc/objc.h>中可以看出id其實(shí)是指向objc_object結(jié)構(gòu)體的指針蚁孔。objc_object只有一個(gè)成員變量 isa,對象可以通過 isa 指針找到其所屬的類惋嚎,這也是為什么id可以表示任意對象的原因杠氢。isa 是一個(gè) Class 類型的成員變量。
注意:在KVO中另伍,isa在運(yùn)行時(shí)會被修改修然,指向一個(gè)中間類,對于編譯器而言质况,isa的指向才是最真實(shí)的類型愕宋。

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;

當(dāng)我們向一個(gè)Objective-C對象發(fā)送消息時(shí),運(yùn)行時(shí)庫會根據(jù)
實(shí)例對象的isa指針找到這個(gè)實(shí)例對象所屬的類结榄。Runtime庫會在類的方法列表由super_class指針找到父類的方法列表直至根類NSObject中去尋找與消息對應(yīng)的selector指向的方法中贝,找到后即運(yùn)行這個(gè)方法。

3.元類(meta-Class)

類自身也是一種對象臼朗,可以叫做“類對象”邻寿。類對象包含一個(gè)指向其類的一個(gè)isa指針( Class _Nonnull isa )

為了調(diào)用類方法,這個(gè)類的isa指針必須指向一個(gè)包含這些類方法的一個(gè)objc_class結(jié)構(gòu)體视哑。這就引出了meta-class的概念绣否,meta-class中存儲著一個(gè)類的所有類方法。
所以挡毅,調(diào)用類方法的這個(gè)類對象的isa指針指向的就是meta-class蒜撮。當(dāng)我們向一個(gè)對象發(fā)送消息時(shí),runtime會在這個(gè)對象所屬的這個(gè)類的方法列表中查找方法跪呈;而向一個(gè)類發(fā)送消息時(shí)段磨,會在這個(gè)類的meta-class的方法列表中查找。

下圖是一個(gè)經(jīng)典的類及相應(yīng)meta-class類的一個(gè)繼承體系圖解:

image.png

從圖中可以看出:
1.每個(gè)實(shí)例對象的類都是類對象耗绿,每個(gè)類對象的類都是元類對象苹支,每個(gè)元類對象的類都是根元類(root meta class的isa指向自身)。即任何NSObject繼承體系下的meta-class都使用NSObject的meta-class作為自己的所屬類误阻,而基類的meta-class的isa指針是指向它自己债蜜。
2.類對象的父類最終繼承自根類對象NSObject,NSObject的父類為nil
3.元類對象(包括根元類)的父類最終繼承自根類對象NSObject

三究反、方法和消息

1.SEL
typedef struct objc_selector *SEL寻定;
SEL sel1 = @selector(func1);
SEL sel2 = NSSelectorFromString(func2);

SEL本質(zhì)上是一個(gè)指向方法的指針。Objective-C在編譯時(shí)奴紧,會依據(jù)每一個(gè)方法的名字特姐、參數(shù)序列晶丘,生成一個(gè)唯一的整型標(biāo)識即SEL黍氮,每一個(gè)方法都對應(yīng)著一個(gè)SEL唐含。所以即使返回值類型或參數(shù)類型不同,方法名相同也會報(bào)錯(cuò)沫浆。

2.IMP
id (*IMP)(id, SEL,...)

IMP的本質(zhì)是函數(shù)指針捷枯,指向方法實(shí)現(xiàn)的地址,直接通過IMP就可以找到各個(gè)方法专执。這樣效率更高淮捆,因?yàn)槔@過了消息傳遞階段,直接定位本股。
SEL就是為了查找方法的最終實(shí)現(xiàn)IMP的攀痊。由于每個(gè)方法對應(yīng)唯一的SEL,因此我們可以通過SEL方便快速準(zhǔn)確地獲得它所對應(yīng)的IMP拄显。

消息發(fā)送和轉(zhuǎn)發(fā)流程可以概括為:消息發(fā)送(Messaging)是 Runtime 通過 selector 快速查找 IMP 的過程苟径,有了函數(shù)指針就可以執(zhí)行對應(yīng)的方法實(shí)現(xiàn);消息轉(zhuǎn)發(fā)(Message Forwarding)是在查找 IMP 失敗后執(zhí)行一系列轉(zhuǎn)發(fā)流程的慢速通道躬审,如果不作轉(zhuǎn)發(fā)處理棘街,則會打日志和拋出異常。

3.Method
typedef struct objc_method *Method
struct objc_method{
    SEL method_name      OBJC2_UNAVAILABLE; // 方法名
    char *method_types   OBJC2_UNAVAILABLE;
    IMP method_imp       OBJC2_UNAVAILABLE; // 方法實(shí)現(xiàn)
}

可以看出method包含SEL和IMP承边,在實(shí)現(xiàn)方法交換時(shí)遭殉,主要原理就是交換SEL和IMP的映射關(guān)系。

參考:http://www.reibang.com/p/46dd81402f63
http://www.reibang.com/p/adf0d566c887
http://www.reibang.com/p/13457a27624c

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末博助,一起剝皮案震驚了整個(gè)濱河市险污,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌富岳,老刑警劉巖罗心,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異城瞎,居然都是意外死亡渤闷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門脖镀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來飒箭,“玉大人,你說我怎么就攤上這事蜒灰∠阴澹” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵强窖,是天一觀的道長凸椿。 經(jīng)常有香客問我,道長翅溺,這世上最難降的妖魔是什么脑漫? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任髓抑,我火速辦了婚禮,結(jié)果婚禮上优幸,老公的妹妹穿的比我還像新娘吨拍。我一直安慰自己,他們只是感情好网杆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布羹饰。 她就那樣靜靜地躺著,像睡著了一般碳却。 火紅的嫁衣襯著肌膚如雪队秩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天昼浦,我揣著相機(jī)與錄音刹碾,去河邊找鬼。 笑死座柱,一個(gè)胖子當(dāng)著我的面吹牛迷帜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播色洞,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼戏锹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了火诸?” 一聲冷哼從身側(cè)響起锦针,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎置蜀,沒想到半個(gè)月后奈搜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盯荤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年馋吗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秋秤。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宏粤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灼卢,到底是詐尸還是另有隱情绍哎,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布鞋真,位于F島的核電站崇堰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜海诲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一繁莹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饿肺,春花似錦、人聲如沸盾似。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽零院。三九已至溉跃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間告抄,已是汗流浹背撰茎。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留打洼,地道東北人龄糊。 一個(gè)月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像募疮,于是被迫代替她去往敵國和親炫惩。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

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