iOS底層-類的底層原理(一)

前言

通常在創(chuàng)建對象的時候熊榛,都會繼承 NSObject去新建一個類疯攒,那么NSObject 繼承誰会喝?或者說類的底層原理是什么末秃?下面來具體探究一下概页。

本文探索過程會涉及到 對象的本質(zhì)

準備工作

  • 新建一個 Project
  • main.m 中添加一個類 ZLObject,打上斷點并執(zhí)行练慕。

案例分析

1. 探索對象的底層
  • $ p obj:查看 obj 對象的地址惰匙。

  • $ x/4gx obj地址:查看 obj 對象的isa及內(nèi)存占用。

  • $ p/x isa地址 & 掩碼地址:與掩碼做與運算

  • $ po 與運算地址:查看關(guān)聯(lián)類

流程如下:

其中掩碼為 __86_64__ 的掩碼地址 0x00007ffffffffff8ULL铃将,最終得到 ZLObject 的地址:0x0000000100008260

2. 繼續(xù)探索

以上面 ZLObject0x0000000100008260 地址项鬼,再次進行 isaISA_MASK 與運算,最終得到 0x0000000100008238 的地址劲阎,還是 ZLObject绘盟。

這就比較奇怪了,為什么都是 ZLObject悯仙,內(nèi)存地址卻不一樣龄毡?

3. 再次探索

再次以新的 ZLObject0x0000000100008238 地址,再次進行 isaISA_MASK 與運算锡垄,最終得到 0x00007fff92c9d0f0 的地址沦零,是 NSObject

對此货岭,有兩個疑問:

  • 兩次的 ZLObject 是否存在的一定的聯(lián)系路操?

  • NSObjectisa 指向了什么?

4. 方法印證

添加下圖方法茴她,并打印其內(nèi)存情況寻拂。

打印結(jié)果如下:

通過上面的案例,得到的結(jié)論是:對象的 isa 是指向 丈牢,也就是 ZLObject 的內(nèi)存地址 0x0000000100008260祭钉,那么類的 isa 指向的是什么?為什么這塊內(nèi)存地址也是 ZLObject己沛。

5. MachO文件分析

有關(guān)MachO文件探索慌核,請移步 MachO文件分析

通過 MachOView 的分析距境,直接定義到 Symbol Table 下查看所有的 symbols 數(shù)據(jù),搜索 class垮卓,得出:

  • 找到了 0x0000000100008260 的內(nèi)存地址垫桂,其符號下標(biāo)就是 _OBJC_CLASS_$_ZLObject,也就是 ZLObject粟按。
  • 找到了 0x0000000100008238 的內(nèi)存地址诬滩,其符號下標(biāo)就是 _OBJC_METACLASS_$_ZLObject,稱為 ZLObject 的元類灭将。

結(jié)論一

  • 對象的 isa 指向

  • 類的 isa 指向 元類

  • 元類 是系統(tǒng)編譯器生成的疼鸟。

MetaClass的本質(zhì)

上面的分析中,提出了兩個疑問庙曙,其中第一個已經(jīng)證實空镜,兩次的 ZLObject,一個是 捌朴,一個是 元類吴攒。那么,NSObjectisa 指向了什么砂蔽?接下來我們繼續(xù)探索洼怔。

通過查看 NSObject.class 的內(nèi)存地址 0x00007fff92c9d118,發(fā)現(xiàn)和之前的 NSObject 地址 0x00007fff92c9d0f0 不一樣察皇,因此 0x00007fff92c9d0f0NSObject元類茴厉。

那么 NSObject元類isa 又指向了什么?

通過運算分析什荣,NSObject元類isa 還是指向 NSObject元類矾缓。

結(jié)論二

  • 元類isa 指向 根元類

  • 根元類isa 還是指向 根元類

  • 對于 NSObject ,它也是 根類稻爬,根類isa 也是指向 根元類

SuperClass的本質(zhì)

上面分析了 ZLObject 類和 NSObject類的 isa 指向情況嗜闻,那么父類 SuperClassisa 指向情況和繼承關(guān)系如何呢?

1. NSObject SuperClass

創(chuàng)建如圖類桅锄,并打印其內(nèi)存情況:

打印結(jié)果如下:

說明:

  • NSObject 的父類是 nil

  • NSObject 的元類的父類還是 NSObject

2. ZLObject SuperClass

首先看一下類的父類是 NSObject 的情況琉雳,打印其元類:

打印結(jié)果如下:

說明:ZLObject 的元類的父類是 NSObject 的元類

3. ZLSubObject SuperClass

創(chuàng)建繼承于 ZLObject 的子類 ZLSubObject,并打印如圖內(nèi)存:

打印情況如下:

說明:ZLSubObject 的元類的父類是 ZLObject 的元類友瘤。

結(jié)論三

  • NSObject 的父類是 nil翠肘,其元類的父類還是 NSObject

  • 父類的元類也有繼承關(guān)系。

最終得到兩個關(guān)系圖辫秧,一個是類的 isa 指向圖束倍,一個是類的繼承鏈圖。

類的 isa 指向圖
類繼承鏈圖

內(nèi)存偏移

1. 普通指針

打印結(jié)果:

說明:常量10處于 常量區(qū) ,可以被 不同 的指針引用绪妹,其引用原理為 值拷貝甥桂。

2. 數(shù)組指針

打印結(jié)果:

說明:

  • 使用數(shù)組 下標(biāo) 取地址,和利用 指針偏移量 取值效果一樣邮旷。不如上圖中是 &c[0]b + 1

  • 數(shù)組的 首地址 也就是數(shù)組 第一個 元素的地址黄选。

  • 指針 偏移量大小 和數(shù)組元素所占用 字節(jié)大小 有關(guān),比如上圖中是 int婶肩,所以打印結(jié)果地址相差 4办陷,也稱 步長

類的內(nèi)存結(jié)構(gòu)

分析源碼可知狡孔,objc_class 方法實現(xiàn)如下:

其內(nèi)存結(jié)構(gòu)圖如下:

因此如果想要得到 bits懂诗,就必須知道 superclasscache 的內(nèi)存字節(jié)數(shù)蜂嗽,再利用內(nèi)存偏移得到 bits苗膝。

由于 isa8 字節(jié),此處不再贅述植旧。

1. superclass

superclassisa 一樣辱揭,也是 8 字節(jié),因為都是 Class 結(jié)構(gòu)體類型

2. cache

cache_t 的有效代碼如下:

cache_t 中的方法和 static 聲明的字段都不是在該結(jié)構(gòu)體內(nèi)病附,所以只需要分析上面的有效代碼问窃,獲取 cache_t 所占用的內(nèi)存大小,即可得到 bits 的內(nèi)存偏移量完沪。

1. 聯(lián)合體之外的 explicit_atomic<uintptr_t>的大杏虮印:
explicit_atomic 為泛型指針,所以其內(nèi)存大小由 <uintptr_t> 決定的覆积,也就是 uintptr_t 的大小听皿,為 8 字節(jié)。也可以使用 sizeof(uintptr_t) 查看其字節(jié)大小宽档。

2. 聯(lián)合體的大形疽獭:

說明:

  • mask_tuint32_t 類型,所以為 4吗冤,uint16_t 類型為 2又厉。

  • <preopt_cache_t *> 為結(jié)構(gòu)體指針,所以為 8椎瘟。

  • 聯(lián)合體內(nèi)部 內(nèi)存共用 覆致,且 互斥 的特性,所以總大小為 8肺蔚。

結(jié)論

cache 所占字節(jié)為 16

bits 的內(nèi)存偏移量為 isa + superclass + cache煌妈,總大小為 32

類的底層數(shù)據(jù)獲取

1. 獲取 bits 數(shù)據(jù):

上圖可得類的首地址為:0x1000081e8,那么以類的首地址偏移 32 字節(jié),就是 bits 声旺。

此時 bits 的數(shù)據(jù)存儲在 $4 中笔链。

在上面分析 objc_class 的結(jié)構(gòu)時,可以對 data() 進行存取數(shù)據(jù)腮猖。

因此鉴扫,可以通過 $4->data() 方法獲取 class_rw_t 內(nèi)存地址:

2. 獲取 class_rw_t 數(shù)據(jù):

這樣 class_rw_t 的數(shù)據(jù)就可以拿到了,但是并不知道所需的屬性和方法具體存在哪里澈缺。

3. 分析 class_rw_t 結(jié)構(gòu)體:

通過 properties()methods() 獲取類的屬性和方法坪创。

4. 獲取 property_array_tlist

5. 獲取 listptr

6. 獲取 property_list_t 的數(shù)據(jù) :

7. 使用 C++數(shù)組 get() 方法,獲取類的屬性 :

8. 同理獲取類的 methods()

最后一步的 get(0) 沒有拿到數(shù)據(jù)姐赡,因此獲取方法和屬性不一樣莱预。

9. 分析 method_t

10. 調(diào)用 big() 函數(shù)。

類的底層探索流程圖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末项滑,一起剝皮案震驚了整個濱河市依沮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枪狂,老刑警劉巖危喉,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異州疾,居然都是意外死亡辜限,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門严蓖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來薄嫡,“玉大人,你說我怎么就攤上這事颗胡『辽睿” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵杭措,是天一觀的道長费什。 經(jīng)常有香客問我,道長手素,這世上最難降的妖魔是什么鸳址? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮泉懦,結(jié)果婚禮上稿黍,老公的妹妹穿的比我還像新娘。我一直安慰自己崩哩,他們只是感情好巡球,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布言沐。 她就那樣靜靜地躺著,像睡著了一般酣栈。 火紅的嫁衣襯著肌膚如雪险胰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天矿筝,我揣著相機與錄音起便,去河邊找鬼。 笑死窖维,一個胖子當(dāng)著我的面吹牛榆综,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播铸史,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼鼻疮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了琳轿?” 一聲冷哼從身側(cè)響起判沟,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎利赋,沒想到半個月后水评,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡媚送,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了寇甸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塘偎。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拿霉,靈堂內(nèi)的尸體忽然破棺而出吟秩,到底是詐尸還是另有隱情,我是刑警寧澤绽淘,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布涵防,位于F島的核電站沪铭,受9級特大地震影響壮池,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杀怠,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一椰憋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赔退,春花似錦橙依、人聲如沸证舟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽女责。三九已至,卻和暖如春创译,著一層夾襖步出監(jiān)牢的瞬間鲤竹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工昔榴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辛藻,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓互订,卻偏偏與公主長得像吱肌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子仰禽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

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