OC類對(duì)象/實(shí)例對(duì)象/元類解析

上下文- 前情概述:

上一篇文章 OC對(duì)象占用內(nèi)存原理 (一文徹底搞懂) 中我們講到 OC 對(duì)象本身是一個(gè)結(jié)構(gòu)體, 這個(gè)結(jié)構(gòu)體只有一個(gè) isa 指針, 關(guān)于 OC 對(duì)象實(shí)際開辟內(nèi)存原理我們搞清楚了. 那么本篇文章就結(jié)合 runtime 來(lái)實(shí)際探討一下 OC 對(duì)象方法查找的具體流程以及方法調(diào)用的原理.

isa

任何數(shù)據(jù)結(jié)構(gòu),只要在恰當(dāng)?shù)奈恢镁哂幸粋€(gè)指針指向一個(gè) class渊涝,那么眉踱,它都可以被認(rèn)為是一個(gè)對(duì)象撮珠。objc_classobjc_objectstruct 指針都能稱為對(duì)象,我們?yōu)榱藚^(qū)分可以把它們分別叫做類對(duì)象和實(shí)例對(duì)象筹裕,其中實(shí)例對(duì)象的 isa 指針指向類對(duì)象 (這個(gè)指向下面會(huì)講)。

OC 中,一個(gè)對(duì)象所屬于哪個(gè)類澜薄,是由它的 isa 指針指向的。這個(gè) isa 指針指向這個(gè)對(duì)象所屬的 class摊册。

個(gè)人建議: 可以適當(dāng)結(jié)合英文意思來(lái)理解, isa -> is a what? -> 你是個(gè)啥.

實(shí)例對(duì)象 | 類對(duì)象 | 元類 的基礎(chǔ)概念區(qū)分

簡(jiǎn)單來(lái)個(gè) ??:
提前創(chuàng)建了一個(gè)類 LBPerson 繼承與 NSObject. 然后創(chuàng)建這個(gè)對(duì)象.

LBPerson * obj = [[LBPerson alloc] init];
  • 實(shí)例對(duì)象 : obj, 其 isa 指向類對(duì)象
  • 類對(duì)象 : LBPerson , 其 isa 指向元類
  • 元類 : 元類就是類對(duì)象所屬的類 , 其 isa 指向根源類, 也就是 NSObject 的元類.


如果我們?cè)趧?chuàng)建一個(gè)子類,繼承與 LBPerson , 那么這個(gè)子類就是上圖中的 Subclass(class) , 實(shí)例化出來(lái)的對(duì)象就是 Instance Of Subclass.

需要注意的是:

  • 任何元類的 isa 都指向根元類. 根源類的 isa 指向它自己. 以此來(lái)實(shí)現(xiàn)一個(gè)完整的內(nèi)循環(huán), 所有的類,都會(huì)有類型, isa 不會(huì)為空.
  • NSObject 的父類為 nil .
  • 根元類的父類指向 NSObject .

那么這三種類型的對(duì)象分別都持有什么呢? 比如說(shuō) 方法到底存在哪個(gè)對(duì)象中? 屬性存在哪個(gè)對(duì)象? 接下來(lái)我們一一探討.

類對(duì)象

類對(duì)象我們通過(guò)源碼來(lái)查看其中保存了哪些內(nèi)容,
shift+ cmd + O, 輸入 objc.


找到 38 行:

typedef struct objc_class *Class;

cmd + 點(diǎn) objc_class, 來(lái)到類對(duì)象的結(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;

稍微介紹一下各個(gè)屬性的意思:

  • isa :上文講述過(guò)
  • super_class :父類肤京,如果該類已經(jīng)是最頂層的根類,那么它為 nil
  • version :類的版本信息,默認(rèn)為 0
  • info :供運(yùn)行期使用的一些位標(biāo)識(shí)茅特。
  • instance_size :該類的實(shí)例變量大小
  • ivars :成員變量的列表
  • methodLists :方法列表
  • cache :緩存結(jié)構(gòu)體桶
  • protocols :協(xié)議列表

類對(duì)象總結(jié):
是一個(gè)功能完整的對(duì)象忘分。特殊之處在于它們是在運(yùn)行時(shí)由編譯器創(chuàng)建的,它沒(méi)有自己的實(shí)例變量(這里區(qū)別于類的成員變量白修,他們是屬于實(shí)例對(duì)象的妒峦,而不是屬于類對(duì)象的,類方法是屬于類對(duì)象自己的)兵睛,但 類對(duì)象中存著成員變量與實(shí)例方法列表肯骇。

存儲(chǔ)內(nèi)容如圖:


實(shí)例對(duì)象

先來(lái)看控制臺(tái)提供給我們的.


我們看到實(shí)例對(duì)象中有屬性, 和 isa. 這也跟我們上一篇博客中探討 OC 對(duì)象占用內(nèi)存原理 得出的結(jié)果是一模一樣.

實(shí)例對(duì)象總結(jié):
當(dāng)我們?cè)诖a中新創(chuàng)建一個(gè)實(shí)例對(duì)象時(shí),拷貝了實(shí)例所屬的類的成員變量祖很,但不拷貝類定義的方法笛丙。調(diào)用實(shí)例方法時(shí),根據(jù)實(shí)例的 isa 指針去尋找方法對(duì)應(yīng)的函數(shù)指針假颇。

存儲(chǔ)內(nèi)容如圖:


元類

OC 的類方法是使用元類的根本原因, 而這也是元類中存儲(chǔ)的最重要的內(nèi)容. 當(dāng)你給類發(fā)消息時(shí)胚鸯,消息是在尋找這個(gè)類的元類的方法列表. 類對(duì)象是元類的實(shí)例. 因此元類存儲(chǔ)著類方法.

存儲(chǔ)內(nèi)容如下:


元類對(duì)象總結(jié):
OC 的類方法是使用元類的根本原因,因?yàn)槠渲写鎯?chǔ)著對(duì)應(yīng)的類對(duì)象調(diào)用的方法即類方法笨鸡。其他時(shí)候都傾向于隱藏元類姜钳,因此真實(shí)世界沒(méi)有人發(fā)送消息給元類對(duì)象。元類的定義和創(chuàng)建看起來(lái)都是編譯器自動(dòng)完成的形耗,無(wú)需人為干涉傲须。

要獲取一個(gè)類的元類,可使用如下定義的函數(shù):

Class objc_getMetaClass(const char* name); //name為類的名字

此外還有一個(gè)獲取對(duì)象所屬的類的函數(shù):

Class object_getClass(id obj) ;

由于類對(duì)象是元類的實(shí)例趟脂,所以當(dāng)傳入的參數(shù)為類名時(shí)泰讽,返回的就是指向該類所屬的元類的指針。

總結(jié)

基于此, 我們可以根據(jù)其存儲(chǔ)內(nèi)容稍微總結(jié)一下

  • 1??: 實(shí)例對(duì)象的 isa 指向類對(duì)象,當(dāng)調(diào)用對(duì)象方法已卸,通過(guò)實(shí)例對(duì)象的 isa 找到類對(duì)象,最終找到對(duì)對(duì)象方法進(jìn)行調(diào)用

  • 2??: 類對(duì)象的 isa 指向元類佛玄,調(diào)用類方法,通過(guò)類對(duì)象中的 isa 找到元類累澡,最終找到元類中的類方法進(jìn)行調(diào)用

  • 3??: 當(dāng)子類的對(duì)象要調(diào)用父類的對(duì)象方法梦抢,先通過(guò)子類的 isa 找到父類的 class. 然后通過(guò) superClass 找到父類的 class 最后找到消息進(jìn)行調(diào)用.


最后要提醒注意的一點(diǎn)是:

根類不一定是 NSObject,因?yàn)楹竺娼榻B的 objc_allocateClassPair 函數(shù)也可以創(chuàng)建出一個(gè)根類愧哟。

元類的實(shí)際應(yīng)用

類對(duì)象和元類對(duì)象的相關(guān)方法:

  • ① : object_getClass 跟隨實(shí)例的 isa 指針奥吩,返回此實(shí)例所屬的類,對(duì)于實(shí)例對(duì)象 (instance) 返回的是類 (class) ,對(duì)于類 (class) 則返回的是元類 (metaclass) .

  • ② : class 方法對(duì)于實(shí)例對(duì)象 (instance) 會(huì)返回類 (class) , 但對(duì)于類 (class) 則不會(huì)返回元類 (metaclass), 而只會(huì)返回類本身蕊梧,即[@"instance" class] 返回的是 __NSCFConstantString , 而 [NSString class] 返回的是 NSString 霞赫。

  • ③ : class_isMetaClass 可判斷某類是否為元類.

  • ④ : 使用 objc_allocateClassPair 可在運(yùn)行時(shí)創(chuàng)建新的類與元類對(duì),使用 class_addMethodclass_addIvar 可向類中增加方法和實(shí)例變量肥矢,最后使用 objc_registerClassPair 注冊(cè)后端衰,就可以使用此類了。這體現(xiàn)了 OC 作為運(yùn)行時(shí)語(yǔ)言的強(qiáng)大之一:在代碼運(yùn)行中動(dòng)態(tài)創(chuàng)建類并添加方法甘改。

至此, 三種不同的類的基礎(chǔ)我們已經(jīng)講完, 下一篇會(huì)基于此基礎(chǔ), 探索方法查找流程.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旅东,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子十艾,更是在濱河造成了極大的恐慌抵代,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忘嫉,死亡現(xiàn)場(chǎng)離奇詭異荤牍,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)榄融,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)救湖,“玉大人愧杯,你說(shuō)我怎么就攤上這事⌒龋” “怎么了力九?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)邑闺。 經(jīng)常有香客問(wèn)我跌前,道長(zhǎng),這世上最難降的妖魔是什么陡舅? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任抵乓,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘灾炭。我一直安慰自己茎芋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布蜈出。 她就那樣靜靜地躺著田弥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铡原。 梳的紋絲不亂的頭發(fā)上偷厦,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音燕刻,去河邊找鬼只泼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛酌儒,可吹牛的內(nèi)容都是我干的辜妓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼忌怎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼籍滴!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起榴啸,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤孽惰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后鸥印,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勋功,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年库说,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狂鞋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡潜的,死狀恐怖骚揍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情啰挪,我是刑警寧澤信不,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站亡呵,受9級(jí)特大地震影響抽活,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锰什,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一下硕、第九天 我趴在偏房一處隱蔽的房頂上張望丁逝。 院中可真熱鬧,春花似錦卵牍、人聲如沸果港。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辛掠。三九已至,卻和暖如春释牺,著一層夾襖步出監(jiān)牢的瞬間萝衩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工没咙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猩谊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓祭刚,卻偏偏與公主長(zhǎng)得像牌捷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涡驮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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

  • iOS底層原理總結(jié) - 探尋OC對(duì)象的本質(zhì) 原文鏈接 對(duì)小碼哥底層班視頻學(xué)習(xí)的總結(jié)與記錄暗甥。面試題部分,通過(guò)對(duì)面試題...
    二斤寂寞閱讀 649評(píng)論 0 4
  • iOS底層原理總結(jié) - 探尋OC對(duì)象的本質(zhì) 對(duì)小碼哥底層班視頻學(xué)習(xí)的總結(jié)與記錄捉捅。面試題部分撤防,通過(guò)對(duì)面試題的分析探索...
    xx_cc閱讀 21,378評(píng)論 31 178
  • (一) 家家戶戶冤冤, 爭(zhēng)爭(zhēng)議議年年棒口, 子子孫孫遍遍寄月? 回回轉(zhuǎn)轉(zhuǎn), 生生世世延延无牵。 (二) 千家不解其緣漾肮, 久爭(zhēng)難...
    喬玉兒閱讀 248評(píng)論 4 11
  • 晨間寫作堅(jiān)持了大概30天,近兩周強(qiáng)烈反彈茎毁,又恢復(fù)到之前的晚起晚睡模式克懊,早晨因?yàn)槠鸬眠t,連這點(diǎn)寶貴的寫作時(shí)間也沒(méi)有了...
    寶媽CC的流水賬閱讀 419評(píng)論 6 12
  • 看到楊樹的葉子充岛,一片片竟然那么完整清晰的模樣保檐,我的心確實(shí)被震了一下耕蝉。細(xì)看崔梗,還是真的,一樹雖嫩卻蓬勃的葉子啊垒在,密密匝...
    小緣小愿閱讀 328評(píng)論 1 2