【譯】Objective-C Runtime

本文詳細(xì)整理了 Cocoa 的 Runtime 系統(tǒng)的知識(shí)腕让,它使得 Objective-C 如虎添翼承粤,具備了靈活的動(dòng)態(tài)特性妆距,使這門(mén)古老的語(yǔ)言煥發(fā)生機(jī)校坑。主要內(nèi)容如下:

  • 引言
  • 簡(jiǎn)介
  • 與 Runtime 交互
  • Rumtime 術(shù)語(yǔ)
  • 消息
  • 動(dòng)態(tài)方法解析
  • 消息轉(zhuǎn)發(fā)
  • 健壯的實(shí)例變量(Non Fragile ivars)
  • Objective-C Associated Objects
  • Method Swizzling
  • 總結(jié)

本文為轉(zhuǎn)載轧飞,出處鏈接后續(xù)補(bǔ)上。撒踪。

引言


曾經(jīng)覺(jué)得Objc特變方便上手过咬,面對(duì)著Cocoa中大量API,只知道簡(jiǎn)單地查看文檔和調(diào)用制妄。還記得初學(xué) Objective-C 時(shí)把[receiver message]當(dāng)成簡(jiǎn)單地方法調(diào)用掸绞,而無(wú)視了“發(fā)送消息”這句話的深刻含義。于是[receiver message]會(huì)被編譯器轉(zhuǎn)化為:

objc_mesgSend(receiver,selector)

如果消息含有參數(shù)耕捞,則為:

objc_mesgSend(receiver, selector, arg1, arg2, ...)

如果消息的接收者能夠找到對(duì)應(yīng)的selector衔掸,那么就相當(dāng)于直接執(zhí)行了接收者這個(gè)對(duì)象的特定方法;否則俺抽,消息要么被轉(zhuǎn)發(fā)敞映,或是臨時(shí)向接收者動(dòng)態(tài)添加這個(gè)selector對(duì)應(yīng)的實(shí)現(xiàn)內(nèi)容,要么就干脆玩完奔潰掉磷斧。

現(xiàn)在可以看出[receiver message]真的不是一個(gè)簡(jiǎn)簡(jiǎn)單單的方法調(diào)用振愿。因?yàn)檫@只是在編譯階段確定了要向接收者發(fā)送message這條消息,而receive將要如何響應(yīng)這條消息弛饭,那就要看運(yùn)行時(shí)發(fā)生的情況來(lái)決定了冕末。

Objective-C 的 Runtime 鑄就了它動(dòng)態(tài)語(yǔ)言的特性, 這些深層次的只是雖然平時(shí)寫(xiě)代碼用的少一些侣颂,但是卻是每個(gè)Objc程序員需要了解的档桃。

簡(jiǎn)介


因?yàn)镺bjc是一門(mén)動(dòng)態(tài)語(yǔ)言,所以它總是想辦法把一些決定工作從編譯鏈接推遲到運(yùn)行時(shí)憔晒。也就是說(shuō)只有編譯器是不夠的藻肄,還需要一個(gè)運(yùn)行時(shí)系統(tǒng)(runtime system)來(lái)執(zhí)行編譯后的代碼。這就是 Objective-C Runtime 系統(tǒng)存在的意義拒担,它是整個(gè)Objc運(yùn)行框架的一塊基石嘹屯。

Runtime 其實(shí)有兩個(gè)版本:"modern"和"legacy"。我們現(xiàn)在用的 Objective-C 2.0 采用的是現(xiàn)行(Modern)版的 Runtime 系統(tǒng)澎蛛,只能運(yùn)行在 iOS 和 OS X 10.5 之后的64位程序中抚垄。而OS X較老的32位程序仍采用 Objective-C 1中得(早期) Legacy 版本的 Runtime 系統(tǒng)。這兩個(gè)版本最大的區(qū)別在于當(dāng)你更改一個(gè)類(lèi)的實(shí)例變量的布局時(shí),在早期版本中你需要重新編譯它的子類(lèi)呆馁,而現(xiàn)行版本就不需要桐经。

Runtime 基本使用C和匯編寫(xiě)的,可見(jiàn)蘋(píng)果為了動(dòng)態(tài)系統(tǒng)的高效而做出的努力浙滤。你可以在這里下載到蘋(píng)果維護(hù)的開(kāi)源代碼阴挣。蘋(píng)果和GNU各自維護(hù)一個(gè)開(kāi)源的runtime版本,這兩個(gè)版本之間都在努力的保持一致纺腊。

與Runtime交互


Objc 從三種不同的層級(jí)上與 Runtime 系統(tǒng)進(jìn)行交互畔咧,分別是通過(guò) Objective-C 源代碼,通過(guò) Foundation 框架的NSObject類(lèi)定義的方法揖膜,通過(guò)對(duì)runtime函數(shù)直接調(diào)用誓沸。

Objective-C源代碼

大部分情況下你就只管寫(xiě)你的Objc代碼就行,runtime系統(tǒng)自動(dòng)在幕后辛勤勞作著壹粟。
還記得引言中舉的例子吧拜隧,消息的執(zhí)行會(huì)使用到一些編譯器為實(shí)現(xiàn)動(dòng)態(tài)語(yǔ)言特性而創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)和函數(shù),Objc中得類(lèi)趁仙、方法和協(xié)議等在 runtime 中都由一些數(shù)據(jù)結(jié)構(gòu)來(lái)定義洪添,這些內(nèi)容在后面會(huì)講到。(比如objc_msgSend函數(shù)及其參數(shù)列表中得idSEL都是啥 )

NSObject的方法

Cocoa中大多數(shù)類(lèi)都繼承于NSObject類(lèi)雀费,也就自然繼承了它的方法干奢。最特殊的例外是NSProxy,它是個(gè)抽象超類(lèi)盏袄,它實(shí)現(xiàn)了一些消息轉(zhuǎn)發(fā)有關(guān)的方法忿峻,可以通過(guò)繼承它來(lái)實(shí)現(xiàn)一個(gè)其他類(lèi)的替身類(lèi)或是虛擬出一個(gè)不存在的類(lèi),說(shuō)白了就是領(lǐng)導(dǎo)把自己展現(xiàn)給大家風(fēng)光無(wú)限貌矿,但是把活都交給幕后小弟去干炭菌。

有的NSObject中得方法起到了抽象接口的作用,比如description方法需要你重載它并為你定義的類(lèi)提供描述內(nèi)容逛漫。NSObject還有些方法能在運(yùn)行時(shí)獲得類(lèi)的信息,并檢查一些特性赘艳,比如class返回對(duì)象的類(lèi)酌毡;isKindOfClass:isMemberOfClass: 則檢查對(duì)象是否在指定的類(lèi)繼承體系中;respondsToSelector:檢查對(duì)象能否響應(yīng)指定的消息蕾管;conformsToProtocol:檢查對(duì)象是否實(shí)現(xiàn)了指定協(xié)議類(lèi)的方法枷踏;methodForSelector:則返回指定方法實(shí)現(xiàn)的地址。

Runtime的函數(shù)

Runtime 系統(tǒng)是一個(gè)由一系列函數(shù)和數(shù)據(jù)結(jié)構(gòu)組成掰曾,具有公共接口的動(dòng)態(tài)共享庫(kù)旭蠕。頭文件存放于/usr/include/objc目錄下。許多函數(shù)允許你用純C代碼來(lái)重復(fù)實(shí)現(xiàn) Objc 中同樣地功能。雖然有一些方法構(gòu)成了NSObject類(lèi)的基礎(chǔ)掏熬,但是你在寫(xiě) Objc 代碼時(shí)一般不會(huì)直接用到這些函數(shù)的佑稠,除非是寫(xiě)一些 Objc 與其他語(yǔ)言的橋接或是底層的debug工作。在Objective-C Runtime Reference中有對(duì) Runtime 函數(shù)的詳細(xì)文檔旗芬。

Runtime術(shù)語(yǔ)


還記得引言中得objc_msgSend:方法吧舌胶,它的真身是這樣的:

id objc_msgSend(id self, SEL op, ...);

下面將會(huì)逐漸展開(kāi)介紹一些術(shù)語(yǔ),其實(shí)它們都對(duì)應(yīng)著數(shù)據(jù)結(jié)構(gòu)疮丛。

SEL

objc_msgSend函數(shù)第二個(gè)參數(shù)類(lèi)型為SEL幔嫂,它是selector在Objc中的表示類(lèi)型(Swift中是Selector類(lèi))。selector是方法選擇器誊薄,可以理解為區(qū)分方法的ID履恩,而這個(gè)ID的數(shù)據(jù)結(jié)構(gòu)是SEL

typedef struct objc_selector *SEL;

其實(shí)它就是個(gè)映射到方法的C字符串,你可以用Objc編譯器命令@selector()或者 Runtime 系統(tǒng)的sel_registerName函數(shù)來(lái)獲得一個(gè)SEL類(lèi)型的方法選擇器呢蔫。

不同類(lèi)中相同名字的方法所對(duì)應(yīng)的方法選擇器是相同的切心,即使方法名字相同而變量類(lèi)型不同也會(huì)導(dǎo)致它們具有相同的方法選擇器,于是 Objc 中方法命名有時(shí)會(huì)帶上參數(shù)類(lèi)型(NSNumber一堆抽象工廠方法拿走不謝)咐刨,Cocoa中有好多長(zhǎng)長(zhǎng)的方法哦昙衅。

id

objc_msgSend第一個(gè)參數(shù)類(lèi)型為id,大家對(duì)它都不陌生定鸟,它是一個(gè)指向類(lèi)實(shí)例的指針:

typedef struc objc_object *id;

objc_object又是啥呢:

struct objc_object { Class isa;};

objc_object結(jié)構(gòu)體包含一個(gè)isa指針就可以順藤摸瓜找到對(duì)象所屬的類(lèi)而涉。

Class

之所以說(shuō)isa是指針是因?yàn)?code>Class其實(shí)是一個(gè)指向objc_class結(jié)構(gòu)體的指針:

typedef struct objc_class *Class;

objc_class就是我們魔道的那個(gè)瓜,里面的東西多著呢:

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;

可以看到運(yùn)行時(shí)一個(gè)類(lèi)還關(guān)聯(lián)了它的超類(lèi)指針联予,類(lèi)名啼县,成員變量,方法沸久,緩存季眷,還有附屬的協(xié)議。
其中objc_ivar_listobjc_method_list分別是成員變量列表和方法列表:

struct objc_ivar_list {
    int ivar_count                                           OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_ivar ivar_list[1]                            OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;

struct objc_method_list {
    struct objc_method_list *obsolete                        OBJC2_UNAVAILABLE;

    int method_count                                         OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;
}

(未完待續(xù)卷胯。子刮。。)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末窑睁,一起剝皮案震驚了整個(gè)濱河市挺峡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌担钮,老刑警劉巖橱赠,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異箫津,居然都是意外死亡狭姨,警方通過(guò)查閱死者的電腦和手機(jī)宰啦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)饼拍,“玉大人赡模,你說(shuō)我怎么就攤上這事√韪” “怎么了纺裁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)司澎。 經(jīng)常有香客問(wèn)我欺缘,道長(zhǎng),這世上最難降的妖魔是什么挤安? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任谚殊,我火速辦了婚禮,結(jié)果婚禮上蛤铜,老公的妹妹穿的比我還像新娘嫩絮。我一直安慰自己,他們只是感情好围肥,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布剿干。 她就那樣靜靜地躺著,像睡著了一般穆刻。 火紅的嫁衣襯著肌膚如雪置尔。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天氢伟,我揣著相機(jī)與錄音榜轿,去河邊找鬼。 笑死朵锣,一個(gè)胖子當(dāng)著我的面吹牛谬盐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诚些,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼飞傀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了诬烹?” 一聲冷哼從身側(cè)響起助析,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椅您,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體寡键,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掀泳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年雪隧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片员舵。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脑沿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出马僻,到底是詐尸還是另有隱情庄拇,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布韭邓,位于F島的核電站措近,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏女淑。R本人自食惡果不足惜瞭郑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鸭你。 院中可真熱鬧屈张,春花似錦、人聲如沸袱巨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)愉老。三九已至场绿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俺夕,已是汗流浹背裳凸。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劝贸,地道東北人姨谷。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像映九,于是被迫代替她去往敵國(guó)和親梦湘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉件甥,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,725評(píng)論 0 9
  • objc_getAssociatedObject返回與給定鍵的特定對(duì)象關(guān)聯(lián)的值捌议。ID objc_getAssoci...
    有一種再見(jiàn)叫青春閱讀 1,585評(píng)論 0 7
  • 本文詳細(xì)整理了 Cocoa 的 Runtime 系統(tǒng)的知識(shí),它使得 Objective-C 如虎添翼引有,具備了靈活的...
    lylaut閱讀 806評(píng)論 0 4
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 735評(píng)論 0 2
  • 我們常常會(huì)聽(tīng)說(shuō) Objective-C 是一門(mén)動(dòng)態(tài)語(yǔ)言瓣颅,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,199評(píng)論 0 7