Objective-C 對(duì)象內(nèi)存模型

Objective-C 是一門面向?qū)ο蟮某绦蛟O(shè)計(jì)語言夭织,它的對(duì)象模型是基于類來建立的仁锯。我們可以在這里下載最新的runtime源碼掐禁,當(dāng)前最新版本為objc4-709.tar.gz

Objective-C中的對(duì)象

NSObject是Objective-C中的基類未玻,NSObject定義在objc4-709/runtime/NSObject.h中:

@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}

NSObject的定義中,我們發(fā)現(xiàn) NSObject只有一個(gè)Class類型的成員變量饭寺,同樣在objc4-709/runtime/objc-private.h中可以找到Class的定義:

typedef struct objc_class *Class;

Class其實(shí)也是一個(gè)結(jié)構(gòu)體阻课,也就是說Objective-C中的類其實(shí)也是一個(gè)結(jié)構(gòu)體。繼續(xù)找下去:

objc4-709/runtime/objc-runtime-new中艰匙,能看到objc_class的定義:

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    ...
    ...
    ...
}

objc_class是繼承自objc_object的限煞,所以O(shè)bjective-C中的類,其實(shí)也是一個(gè)對(duì)象员凝。

objc4-709/runtime/objc-private.h中可以找到objc_object對(duì)象的定義:

struct objc_object {
private:
    isa_t isa;

public:
    Class ISA();
    Class getIsa();

    void initIsa(Class cls /*nonpointer=false*/);
    void initClassIsa(Class cls /*nonpointer=maybe*/);
    void initProtocolIsa(Class cls /*nonpointer=maybe*/);
    void initInstanceIsa(Class cls, bool hasCxxDtor);
    Class changeIsa(Class newCls);
    ...
    ...
    ...
};

在Objective-C 中最基本的數(shù)據(jù)結(jié)構(gòu)就是:struct objc_object

Objective-C中的對(duì)象本質(zhì)上是一個(gè)結(jié)構(gòu)體

id類型

在同一個(gè)文件中署驻,我們還能找到Objective-C中id的定義:

typedef struct objc_object *id;

能看到, id 其實(shí)就是一個(gè) struct objc_object 類型的指針绊序。但是 id 不是 NSObject * 硕舆,為什么可以指向任意的 NSObject 對(duì)象呢?因?yàn)?objc_object 只有一個(gè) Class 類型的 isa 變量骤公,而這個(gè)結(jié)構(gòu),恰恰和 NSObject 的定義一致扬跋。

這樣阶捆,NSObject對(duì)象的首地址處的內(nèi)容,就能用id指向了钦听。因?yàn)楸举|(zhì)上洒试,對(duì)象的數(shù)據(jù)都是由struct存放的。

Class

對(duì)象的類不僅描述了對(duì)象的數(shù)據(jù):對(duì)象占用的內(nèi)存大小朴上、成員變量的類型和布局等垒棋,而且也描述了對(duì)象的行為:對(duì)象能夠響應(yīng)的消息、實(shí)現(xiàn)的實(shí)例方法等痪宰。

在 Objective-C 中有一個(gè)非常特殊的類 NSObject 叼架,絕大部分的類都繼承自它畔裕。它是 Objective-C 中的兩個(gè)根類(rootclass)之一,另外一個(gè)是 NSProxy乖订。同樣的扮饶,我們打開文件 NSObject.h ,可以看到 NSObject 類其實(shí)就只有一個(gè)成員變量 isa 乍构,所有繼承自 NSObject 的類也都會(huì)有這個(gè)成員變量甜无。

如果把類的實(shí)例看成一個(gè) C 語言的結(jié)構(gòu)體(struct),上面說的 isa 指針就是這個(gè)結(jié)構(gòu)體的第一個(gè)成員變量哥遮,而類的其它成員變量依次排列在結(jié)構(gòu)體中岂丘。排列順序如下圖所示:


class-member

對(duì)象的實(shí)例方法調(diào)用時(shí),通過對(duì)象的 isa 在類中獲取方法的實(shí)現(xiàn)眠饮。
類對(duì)象的類方法調(diào)用時(shí)奥帘,通過類的 isa 在元類中獲取方法的實(shí)現(xiàn)。

當(dāng)一個(gè)對(duì)象的實(shí)例方法被調(diào)用的時(shí)候君仆,會(huì)通過isa找到相應(yīng)的類翩概,然后在該類的class_data_bits_t中去查找方法。class_data_bits_t是指向了類對(duì)象的數(shù)據(jù)區(qū)域返咱。在該數(shù)據(jù)區(qū)域內(nèi)查找相應(yīng)方法的對(duì)應(yīng)實(shí)現(xiàn)钥庇。

元類(meta-class)之所以重要,是因?yàn)樗鎯?chǔ)著一個(gè)類的所有類方法咖摹。每個(gè)類都會(huì)有一個(gè)單獨(dú)的meta-class评姨,因?yàn)槊總€(gè)類的類方法基本不可能完全相同。

元類(metaclass)

因?yàn)轭愐彩且粋€(gè)對(duì)象萤晴,那么類也必須是另一個(gè)類的實(shí)例吐句,有點(diǎn)繞,可以理解成Class是元類的對(duì)象店读。元類保存了類方法的列表嗦枢。當(dāng)一個(gè)類的方法被調(diào)用時(shí),元類會(huì)首先查找它本身是否有該類方法的實(shí)現(xiàn)屯断,如果沒有文虏,則該元類會(huì)向它的父類查找該方法,直到一直找到繼承鏈的頭殖演。

元類 (metaclass) 也是一個(gè)對(duì)象氧秘,那么元類的 isa 指針又指向哪里呢?為了設(shè)計(jì)上的完整趴久,所有的元類的 isa 指針都會(huì)指向一個(gè)根元類 (root metaclass)丸相。根元類 (root metaclass) 本身的 isa 指針指向自己,這樣就行成了一個(gè)閉環(huán)彼棍。上面提到灭忠,一個(gè)對(duì)象能夠接收的消息列表是保存在它所對(duì)應(yīng)的類中的膳算。在實(shí)際編程中,我們幾乎不會(huì)遇到向元類發(fā)消息的情況更舞,那它的 isa 指針在實(shí)際上很少用到畦幢。不過這么設(shè)計(jì)保證了面向?qū)ο蟮母蓛簦此惺挛锒际菍?duì)象缆蝉,都有 isa 指針宇葱。

對(duì)應(yīng)關(guān)系的圖如下圖,下圖很好的描述了對(duì)象刊头,類黍瞧,元類之間的關(guān)系:
(圖片源自 這里

class-diagram

我們?cè)賮砜纯蠢^承關(guān)系,由于類方法的定義是保存在元類 (metaclass) 中原杂,而方法調(diào)用的規(guī)則是印颤,如果該類沒有一個(gè)方法的實(shí)現(xiàn),則向它的父類繼續(xù)查找穿肄。所以年局,為了保證父類的類方法可以在子類中可以被調(diào)用,所以子類的元類會(huì)繼承父類的元類咸产,換而言之矢否,類對(duì)象和元類對(duì)象有著同樣的繼承關(guān)系。

既然類是一個(gè)對(duì)象脑溢,那么元類是一個(gè)對(duì)象嗎僵朗?其實(shí)元類也是一個(gè)對(duì)象,它是根元類(root metaclass)的實(shí)例屑彻。

那么验庙,根元類呢?這么循環(huán)下去什么時(shí)候是個(gè)頭社牲。其實(shí)根元類所屬的類也是根元類粪薛,即它本身。根元類指的就是根類的元類搏恤,也就是根類 NSObject 的元類汗菜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市挑社,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌巡揍,老刑警劉巖痛阻,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異腮敌,居然都是意外死亡阱当,警方通過查閱死者的電腦和手機(jī)俏扩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弊添,“玉大人录淡,你說我怎么就攤上這事∮桶樱” “怎么了嫉戚?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)澈圈。 經(jīng)常有香客問我彬檀,道長(zhǎng),這世上最難降的妖魔是什么瞬女? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任窍帝,我火速辦了婚禮,結(jié)果婚禮上诽偷,老公的妹妹穿的比我還像新娘坤学。我一直安慰自己,他們只是感情好报慕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布深浮。 她就那樣靜靜地躺著,像睡著了一般卖子。 火紅的嫁衣襯著肌膚如雪略号。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天洋闽,我揣著相機(jī)與錄音玄柠,去河邊找鬼。 笑死诫舅,一個(gè)胖子當(dāng)著我的面吹牛羽利,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刊懈,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼这弧,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了虚汛?” 一聲冷哼從身側(cè)響起匾浪,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卷哩,沒想到半個(gè)月后蛋辈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年冷溶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了渐白。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逞频,死狀恐怖纯衍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苗胀,我是刑警寧澤襟诸,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站柒巫,受9級(jí)特大地震影響励堡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜堡掏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一应结、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泉唁,春花似錦鹅龄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拴鸵,卻和暖如春玷坠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劲藐。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工八堡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人聘芜。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓兄渺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親汰现。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挂谍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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