iOS底層探索之類的結(jié)構(gòu)(上)

回顧

在之前的幾篇博客里面,我們知道了對象的本質(zhì)結(jié)構(gòu)體(iOS底層探索之對象的本質(zhì)和類的關(guān)聯(lián)特性initIsa(上)),也了解了結(jié)構(gòu)體的內(nèi)存對齊(結(jié)構(gòu)體底層探索),也分析了下alloc的底層的源碼(alloc底層探索),也知道了實(shí)例化一個對象,底層是通過isa進(jìn)行關(guān)聯(lián)的。但一直都沒有探索下,那么接下來,我們就去底層看看類,揭開類神秘面紗。

類的結(jié)構(gòu)探索分析.png

類的猜想

首先看看下面??這個,我們實(shí)例化一個對象,在斷點(diǎn)處進(jìn)行調(diào)試

實(shí)例化一個對象

通過打印對象stu的地址,得到ISA,然后和掩碼0x00007ffffffffff8&運(yùn)算,可以得到

(lldb) x/4gx stu
0x10072a850: 0x011d800100008339 0x0000000000000000
0x10072a860: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x011d800100008339 & 0x00007ffffffffff8
(long) $1 = 0x0000000100008338
(lldb) po 0x0000000100008338
JPStudent

那么我們再作一個猜想,類是不是也有一個ISA,那么同步上面的操作看看

(lldb) x/4gx 0x0000000100008338
0x100008338: 0x0000000100008310 0x00000001000082c0
0x100008348: 0x00000001006ac3e0 0x000180200000000f
(lldb) p/x 0x0000000100008310 & 0x00007ffffffffff8
(long) $3 = 0x0000000100008310
(lldb) po 0x0000000100008310
JPStudent

我的天哪!


我的天那!

打印出來的是一模模一樣樣,都打印了JPStudent,地址完全不一樣??!一個是0x0000000100008338,一個是0x0000000100008310。那么類和對象一樣,會在內(nèi)存中無限開辟,不只存在一個類嗎?那么我們?nèi)ヲ?yàn)證一下!

//MARK: - 分析類對象內(nèi)存存在個數(shù)
void jpTestClassNum(void){
    Class class1 = [JPStudent class];
    Class class2 = [JPStudent alloc].class;
    Class class3 = object_getClass([JPStudent alloc]);
    Class class4 = [JPStudent alloc].class;
    NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
}

打印結(jié)果

0x100008338-
0x100008338-
0x100008338-
0x100008338

從打印的結(jié)果來看,說明類只有一個,類在內(nèi)存中有且只有一個。
那么0x0000000100008310,顯然不是,那么它是誰呢?是NSObject嗎?

元類

(lldb) p/x NSObject.class
(Class) $5 = 0x000000010036a140 NSObject

那么不是NSObject,是什么呢?它是一個新的東西,是什么東東呢?我們通過爛蘋果(MachoOView)可以查看

在這里插入圖片描述

在編譯的可以執(zhí)行文件中,除了我們熟悉的 _OBJC_CLASS_$_JPStudent,還多了一個 _OBJC_METACLASS_$_JPStudent,但是我工程代碼里面并沒有去創(chuàng)建這個啊?在結(jié)構(gòu)體的內(nèi)存對齊(結(jié)構(gòu)體底層探索)里面我們知道了,對象的結(jié)構(gòu)里面有個ISA,指向類,那么類的ISA指向誰呢?沒錯,就是指向元類(META),

元類META是由系統(tǒng)生成和編譯的

根元類

那么元類ISA指向哪里呢?

(lldb) x/4gx 0x0000000100008310
0x100008310: 0x000000010036a0f0 0x00000001000082e8
0x100008320: 0x000000010072adf0 0x0001e03100000007
(lldb) p/x 0x000000010036a0f0 & 0x00007ffffffffff8
(long) $6 = 0x000000010036a0f0
(lldb) po 0x000000010036a0f0
NSObject

從打印結(jié)果來看元類ISA指向了根元類(NSObject),那么根元類ISA指向哪里呢?

根元類指向

lldb調(diào)試,可以看到根元類指向了自己

對象 isa -> 類 isa -> 元類 isa -> 根元類 isa

根元類 isa -> 根元類 isa

來個圖唄!這不好理解??!
好,那么我就來個圖,讓大家好理解!

isa 走位

isa走位

從圖中可以分析得出每個對象都有元類和根元類,根元類指向自己

代碼測試驗(yàn)證

    // NSObject實(shí)例對象
     NSObject *object1 = [NSObject alloc];
    // NSObject類
     Class class1 = object_getClass(object1);
     // NSObject元類
     Class metaClass = object_getClass(class1);
     // NSObject根元類
     Class rootMetaClass = object_getClass(metaClass);
     // NSObject根根元類
     Class rootRootMetaClass = object_getClass(rootMetaClass);
     NSLog(@"\n%p 實(shí)例對象\n%p 類\n%p 元類\n%p 根元類\n%p 根根元類",object1,class1,metaClass,rootMetaClass,rootRootMetaClass);

控制臺打印

0x10060d620 實(shí)例對象
0x10036a140 類
0x10036a0f0 元類
0x10036a0f0 根元類
0x10036a0f0 根根元類

元類繼承鏈

我們都知道類有繼承關(guān)系,那么元類也有繼承關(guān)系嗎?

// JPPerson元類
     Class pMetaClass = object_getClass(JPPerson.class);
     Class psuperClass = class_getSuperclass(pMetaClass);
     NSLog(@"%@ - %p",psuperClass,psuperClass);

     // JPStudent -> JPPerson -> NSObject
     // 元類也有一條繼承鏈
     Class sMetaClass  = object_getClass(JPStudent.class);
     Class ssuperClass = class_getSuperclass(tMetaClass);
     NSLog(@"%@ - %p",ssuperClass,ssuperClass);

     // NSObject 根類特殊情況
     Class nsuperClass = class_getSuperclass(NSObject.class);
     NSLog(@"%@ - %p",nsuperClass,nsuperClass);
     // 根元類 -> NSObject
     Class rnsuperClass = class_getSuperclass(metaClass);
     NSLog(@"%@ - %p",rnsuperClass,rnsuperClass);

打印結(jié)果

 NSObject - 0x10036a0f0
 JPPerson - 0x100008300
 (null) - 0x0
 NSObject - 0x10036a140

從以上代碼和運(yùn)行結(jié)果來看,元類也是有繼承關(guān)系的

  • JPPerson的元類是NSObject
  • NSObject的父類是null,沒有爸爸??
  • NSObject根元類的父類是0x10036a140,這和上面的NSObject的類的地址0x10036a140,是一模模一樣樣,NSObject根元類又指向了NSObject這個類。

萬物皆來自于NSObjectNSObject指向了null,這和太極里面的,無中生有有點(diǎn)像!

來個圖吧!上面的代碼看著有點(diǎn)懵??!


類的繼承關(guān)系圖

小結(jié)

在OC里面,對象主要分為三種,

  1. instance對象(實(shí)例對象)
  2. class對象(類對象) ,通過object_getClass(傳入類)方法獲取
  3. meta-class對象(元類對象),通過object_getClass(傳入元類)方法獲取

最后補(bǔ)上一個更詳細(xì)的圖,蘋果官方圖

蘋果官方圖

類的結(jié)構(gòu)

打開蘋果的開源的源碼,可以看到類的底層結(jié)構(gòu)


類的底層結(jié)構(gòu)
  • 默認(rèn)有個ISA
  • 指向父類的指針superclass
  • cache
  • bits

這個bits有個class_rw_t *,class_rw_t里面有一些方法列表,屬性列表,成員變量等等信息,我們看看源碼

class_rw_t核心方法

那么這些我們熟悉的類的信息,該怎么獲取,怎么查看呢?
請看下個博客分析。。。。

??請收藏+關(guān)注,評論 + 轉(zhuǎn)發(fā),以免你下次找不到我,哈哈????

??歡迎大家留言交流,批評指正,互相學(xué)習(xí)??,提升自我??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容