回顧
在之前的幾篇博客里面,我們知道了對象的本質(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)的。但一直都沒有探索下類,那么接下來,我們就去底層看看類,揭開類神秘面紗。

類的猜想
首先看看下面??這個,我們實(shí)例化一個對象,在斷點(diǎn)處進(jìn)行調(diào)試
通過打印對象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 走位
從圖中可以分析得出每個對象都有元類和根元類,根元類指向自己
代碼測試驗(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這個類。
萬物皆來自于
NSObject,NSObject指向了null,這和太極里面的,無中生有有點(diǎn)像!
來個圖吧!上面的代碼看著有點(diǎn)懵??!
小結(jié)
在OC里面,對象主要分為三種,
-
instance對象(實(shí)例對象) -
class對象(類對象) ,通過object_getClass(傳入類)方法獲取 -
meta-class對象(元類對象),通過object_getClass(傳入元類)方法獲取
最后補(bǔ)上一個更詳細(xì)的圖,蘋果官方圖
類的結(jié)構(gòu)
打開蘋果的開源的源碼,可以看到類的底層結(jié)構(gòu)
- 默認(rèn)有個
ISA - 指向父類的指針
superclass cachebits
這個bits有個class_rw_t *,class_rw_t里面有一些方法列表,屬性列表,成員變量等等信息,我們看看源碼
那么這些我們熟悉的類的信息,該怎么獲取,怎么查看呢?
請看下個博客分析。。。。
??請收藏+關(guān)注,評論 + 轉(zhuǎn)發(fā),以免你下次找不到我,哈哈????
??歡迎大家留言交流,批評指正,互相學(xué)習(xí)??,提升自我??