關(guān)于objc_runtime的消息機制(二)

接上篇荠列,我們已經(jīng)大概的聊完了c++的虛函數(shù)實現(xiàn)機制类浪。間接尋址體現(xiàn)在虛函數(shù)表的實現(xiàn)上。虛函數(shù)表由編譯負(fù)責(zé)幫我們維護(hù)肌似。我們來回頭捋一捋函數(shù)調(diào)用過程的變化费就。在c中 函數(shù)名直接被譯為函數(shù)指針(地址),調(diào)用的過程就是直接跳轉(zhuǎn)到目的地址執(zhí)行(當(dāng)然,這個跳轉(zhuǎn)不是普通的命令跳轉(zhuǎn)川队,還包含著cpu寄存器狀態(tài)的壓棧 等等力细,不做細(xì)談。)固额。到了c++中眠蚂,對虛函數(shù)的調(diào)用就有了間接尋址了,這個函數(shù)的調(diào)用過程包括了:
. 1 根據(jù)對象地址找到對象內(nèi)存區(qū)域
. 2 取出位于對象內(nèi)存頭部空間的虛函數(shù)表基址
. 3 查表 找到虛函數(shù)的具體地址
. 4 有了函數(shù)地址 然后就可以調(diào)用了斗躏。
總之 逝慧,間接無非就是建立尋址表,將直接的地址翻譯變?yōu)殚g接尋址啄糙。有了c++的虛函數(shù)其實已經(jīng)可以實現(xiàn)面向?qū)ο笾幸粋€重要的概念:多態(tài)笛臣。但是 程序員是能夠輕易滿足的么?顯然不是啊隧饼。這哪夠沈堡?虛函數(shù)表是編譯器負(fù)責(zé)維護(hù)和實現(xiàn)的,程序員并不能直接的操作和更改(其實是可以的桑李,畢竟我們知道了對象的首段地址就是基地址表,我們可以通過更改這個表來實現(xiàn),但是這些都不是C++設(shè)計者的本意踱蛀,且這樣的代碼寫出來可讀性性極差窿给,更別說什么維護(hù)了)。
這就牽扯出本文將提及的終極大殺器(蘋果大法好,不過我還是喜歡巨硬率拒。)object c 被稱作動態(tài)語言崩泡,這個動態(tài)該如何解釋呢?還是用c來做對比猬膨。c中每一個標(biāo)識符(變量)都必須有一個類型角撞,基本類型 int char float 等等,自定義類型 struct勃痴。這個類型一經(jīng)聲明谒所,其實該對象在內(nèi)存中的空間模型也就固定了(內(nèi)存空間模型包括所占字節(jié)的大小,以及自定義結(jié)構(gòu)體中沛申,各個字段的內(nèi)存區(qū)域分配)劣领。object c 不是這樣的語言。id object = *(賦值號右邊的對象是什么類型就是什么類型铁材。先記住這句話 一會兒就能體會到)尖淘。 簡單的推測,id或許是一個指針類型,因為指針?biāo)甲止?jié)數(shù)是恒定不變的啊著觉,不管什么類型的指針都可以進(jìn)行相互賦值(將32個字節(jié)的struct 賦值給int,多出來的28個字節(jié)也沒地擱啊村生,所以說指針是程序設(shè)計中最成功的概念之一)。于是我們跳轉(zhuǎn)到id的定義看到這樣的代碼

typedef struct objc_object *id;

果不其然 id 是一個指向objc_object結(jié)構(gòu)體的指針饼丘。這時候引發(fā)了我們的好奇繼續(xù)跳轉(zhuǎn)到定義

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

看到objc_object中只有一個成員 Class類型的 isa趁桃。Class又是是什么呢

typedef struct objc_class *Class;

Class其實還是一個指針類型 指向的是objc_class結(jié)構(gòu)體,這時候我們繼續(xù)跳轉(zhuǎn)到定義 可以看到objc_class結(jié)構(gòu)體的定義

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

這就相當(dāng)有趣了,這個結(jié)構(gòu)體中的字段似乎是在描述一個'類'的信息肄鸽,比如 name('類'的名稱) version ('類'的版本號) 另外還要兩個重要的成員

struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists 

根據(jù)名字 卫病,一個是成員變量列表 一個是方法列表。有了這些信息贴捡,對于一個有面向?qū)ο缶幊探?jīng)驗的碼農(nóng)忽肛,這些就可以描述一個類了呀。之所以前面用單引號的'類'烂斋,是我故意要做區(qū)分屹逛。還記得剛接觸面向?qū)ο笳Z言時那種不知所云的感覺么。各種書上在描述類時經(jīng)常會提到的字眼就是 設(shè)計模板 設(shè)計圖紙汛骂。類就使我們用代碼去描述的一個抽象罕模,它會被編譯器具象為內(nèi)存中的實際對象。這時候我們就會有了這么一個思考帘瞭,對啊淑掌,我們平時定義類,類信息是由編譯器負(fù)責(zé)維護(hù)的蝶念。一旦編譯完成抛腕,內(nèi)存中關(guān)于類的很多信息就消失了(當(dāng)然也完全沒必要存在芋绸,比如類的名字)。為什么object c要大費周章的用一個結(jié)構(gòu)體的變量的去保存這些信息呢担敌?如果是從文章一開始就跟緊"計算機科學(xué)中,任何問題都可以通過增加一層間接尋址來實現(xiàn)"這一思路的讀者摔敛,此時應(yīng)該一眼洞穿apple的用意。動態(tài)啊全封,動態(tài)马昙。每一個對象有一個指向它所屬'類'的指針,這個'類'實際上是存在于內(nèi)存中保存著類信息的結(jié)構(gòu)體變量,不同于以往的類信息只是編譯前安安靜靜的躺在編輯器中刹悴。有了這個'類'結(jié)構(gòu)體變量行楞,我們就真的可以為所欲為了。想想都美妙土匀,本來一旦定義了一個類律姨,類的聲明代碼在編譯前一經(jīng)確定影锈,編譯后就沒它啥事了〗杂洌現(xiàn)在是有了一個結(jié)構(gòu)體保存這些信息怀薛,每個對象都有一個指向所屬'類'的指針。我們一旦改變了結(jié)構(gòu)體中的內(nèi)容钓丰,是不是就改變了對象的'類'呢。結(jié)構(gòu)體中有方法列表每币,我們給這個列表添加一個表象携丁,是不是就等于為對象的'類'動態(tài)(因為這一切都是運行時能夠進(jìn)行的)的添加了一個方法呢。
現(xiàn)在我們就對了oc的動態(tài)性有了直觀的感受,有了'類'結(jié)構(gòu)體兰怠。我們看到的以下代碼

NSUInteger lenght = [str length];

就不再是普通的函數(shù)調(diào)用了梦鉴, 我們稱之為消息發(fā)送。str 是這個消息的接受者揭保。實際上以上的代碼會被編譯為

objc_msgSend(str, @selector(length));

這里肥橙,利用runtime為我們提供的 objc_msgSend函數(shù),我們向str發(fā)送了一條消息,通過str中的isa指針找到'類'結(jié)構(gòu)體秸侣,在結(jié)構(gòu)體的方法列表中尋找到相應(yīng)的函數(shù)實現(xiàn)存筏,然后調(diào)用。事實上味榛,如果該'類'的方法列表中沒有搜尋到椭坚,還會繼續(xù)的向父'類'去搜尋,請大家注意到Class _Nullable super_class OBJC2_UNAVAILABLE ,super_class 這個成員變量 它也是指向'類'結(jié)構(gòu)體的指針搏色,它指向的是當(dāng)前對象所屬'類'的父'類' 善茎。總之消息就這樣在這些繼承關(guān)系的'類'中傳遞频轿,直到找到合適的處理方法垂涯,或者最終也沒有找到烁焙,跑出異常。其實有了將類的信息儲存于內(nèi)存中耕赘,實現(xiàn)了一層間接尋址的概念骄蝇,其他的都是水到渠成的。文章并未提到元類的概念鞠苟,請讀者自行搜索別的文章讀乞榨,有了這篇文章做鋪墊,讀起來也定會很輕松当娱。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吃既,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子跨细,更是在濱河造成了極大的恐慌鹦倚,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冀惭,死亡現(xiàn)場離奇詭異震叙,居然都是意外死亡,警方通過查閱死者的電腦和手機散休,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門媒楼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人戚丸,你說我怎么就攤上這事划址。” “怎么了限府?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵夺颤,是天一觀的道長。 經(jīng)常有香客問我胁勺,道長世澜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任署穗,我火速辦了婚禮寥裂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘案疲。我一直安慰自己抚恒,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布络拌。 她就那樣靜靜地躺著俭驮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上混萝,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天遗遵,我揣著相機與錄音,去河邊找鬼逸嘀。 笑死车要,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的崭倘。 我是一名探鬼主播翼岁,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼司光!你這毒婦竟也來了琅坡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤残家,失蹤者是張志新(化名)和其女友劉穎榆俺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坞淮,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡茴晋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了回窘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诺擅。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖啡直,靈堂內(nèi)的尸體忽然破棺而出掀虎,到底是詐尸還是另有隱情,我是刑警寧澤付枫,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站驰怎,受9級特大地震影響阐滩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜县忌,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一掂榔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧症杏,春花似錦装获、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春精肃,著一層夾襖步出監(jiān)牢的瞬間秤涩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工司抱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留筐眷,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓习柠,卻偏偏與公主長得像匀谣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子资溃,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

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

  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,556評論 33 466
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉武翎,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評論 0 9
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,516評論 1 51
  • 某天在微博上看到一位叫吳紅真的作者后频,作品全是針管畫,還公布了過程圖暖途。驚嘆其心思細(xì)膩卑惜!受此啟發(fā),也想著畫上一幅驻售,看看...
    云影拂塵閱讀 2,651評論 18 26
  • 201705 【月度檢視】 標(biāo)題:2017-05【30天月度檢視】姓名( #基本情況#(寫孩子的)姓名:辰 年齡:...
    奔跑的鄭同學(xué)閱讀 505評論 0 0