004--OC對(duì)象原理探究 - isa走位及對(duì)象繼承鏈

引言

接上篇文章003-OC對(duì)象原理探究 - isa 和 nonpointer,本文將通過(guò)實(shí)際代碼演示,探究如何探究isa的走向,以及對(duì)象的繼承關(guān)系。

ISA走位探究

一、拿到ISA_MASK(isa掩碼)
上期我們說(shuō)道蘋(píng)果對(duì)isa的優(yōu)化,獲取對(duì)象,是根據(jù)isa的mask來(lái)得到的,那么我們先把ISA_MASK取出

__arm64__
#     define ISA_MASK        0x0000000ffffffff8ULL
__x86_64__
#     define ISA_MASK        0x00007ffffffffff8ULL

ULL表示unsigned long long
二、代碼實(shí)操
我們新建一個(gè)類(lèi)QLDog,創(chuàng)建dog對(duì)象,打上斷點(diǎn),進(jìn)入lldb調(diào)試模式

image.png

在控制臺(tái)輸入
1、p/x dog,得到dog對(duì)象的地址。(p/xlldb指令,請(qǐng)自行g(shù)oogle搜索lldb常用指令學(xué)習(xí))
image.png

2、接著輸入x/4gx 0x00006000031385a0,得到dog的內(nèi)存結(jié)構(gòu)
image.png

3、此時(shí)猜想0x0000000109f35360是不是我們對(duì)象的isa?那么我們只需要與isa_mask做一次&即可
4、執(zhí)行指令p/x 0x0000000109f35360 & 0x00007ffffffffff8,得到(long) $2 = 0x0000000109f35360,接著po 0x0000000109f35360可得到如下結(jié)果:
image.png
可見(jiàn)0x0000000109f35360為當(dāng)前對(duì)象的isa
-------分割線(xiàn)-------
5、我們繼續(xù)探索,繼續(xù)調(diào)試x/4gx 0x0000000109f35360的內(nèi)存結(jié)構(gòu)如下:
image.png

6、我們猜想,0x0000000109f35338是否也為0x0000000109f35360isa呢?我們重復(fù)與isa_mask&操作:
image.png

7、很驚奇的發(fā)現(xiàn),最終打印的也是QLDog。但是兩個(gè)QLDog的地址不一樣,分別是0x0000000109f353600x0000000109f35338,這是為什么呢?按照這個(gè)猜想,類(lèi)對(duì)象在內(nèi)存中是否可以無(wú)限開(kāi)辟?也就是類(lèi)對(duì)象是否是不只一個(gè)類(lèi)。

驗(yàn)證

測(cè)試代碼:

Class cls1 = [QLDog class];
Class cls2 = [QLDog alloc].class;
Class cls3 = object_getClass([QLDog alloc]);
Class cls4 = [QLDog alloc].class;
    
NSLog(@"\n%p--\n%p--\n%p--\n%p--",cls1,cls2,cls3,cls4);

運(yùn)行后,打印結(jié)果如下:

image.png

打印結(jié)果的地址與dog對(duì)象一致,都是0x00006000031385a0,證明了我們前面的猜想:0x00006000031385a0為類(lèi)QLDog,而0x0000000109f35338不是類(lèi)。那它是什么東西?
接下來(lái)我借助一個(gè)工具
image.png

來(lái)分析編譯后的代碼是什么樣子的。
工程中,products文件夾內(nèi)的可執(zhí)行文件(.app或者macho)show in finder,找到可執(zhí)行文件后,直接拖入MachOView工具中(.app要顯示包內(nèi)容,里面黑色的可執(zhí)行文件就是)。
拖入MachOView后,找到Symbol table下的Symbols,搜索QLDog可看到我們的類(lèi):
image.png

其中有幾個(gè)value是系統(tǒng)生成的,我們這里只需關(guān)注_OBJC_METACLASS_$_QLDog即可。metaclass是元類(lèi)的意思。由此結(jié)合上面的探索可知,我們探索對(duì)象dog的內(nèi)存結(jié)構(gòu),得到對(duì)象的isa,&上isa_mask得到類(lèi)QLDog,接著對(duì)其內(nèi)存窺探,得到類(lèi)的isa,接著&上isa_mask得到一個(gè)元類(lèi)。
到此為止,我們的isa探索走向?yàn)椋?code>對(duì)象isa---類(lèi)isa---元類(lèi)isa

我們重復(fù)以上的p/xx/4gx調(diào)試指令,最終得到

image.png

我們對(duì)NSObject類(lèi)的內(nèi)存進(jìn)行解析:
image.png
所得到的結(jié)果,與上圖的最終結(jié)果一致。
由此可總結(jié)isa的走向:(請(qǐng)與繼承鏈區(qū)分)
image.png

解釋?zhuān)?br> 1、任何的對(duì)象的isa,會(huì)找到自己的類(lèi)
2、自己的類(lèi)的isa,會(huì)找到自己的類(lèi)的元類(lèi)
3、元類(lèi)的isa,會(huì)找到根元類(lèi)
4、根元類(lèi)的isa最終找到自己

繼承鏈探索

對(duì)象的繼承

設(shè)計(jì)代碼如下:

QLDog *dog = [QLDog alloc];
Class dogSuperClass = [dog superclass];
Class superClass1 = [dogSuperClass superclass];
Class superClass2 = [superClass1 superclass];
Class superClass3 = [superClass2 superclass];
Class superClass4 = [superClass3 superclass];
    
NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",dog,dog,dogSuperClass,dogSuperClass,superClass1,superClass1,superClass2,superClass2,superClass3,superClass3,superClass4,superClass4);

打印結(jié)果如下:

image.png

由此可得對(duì)象繼承鏈為:dog——>person——>NSObject——>nil

類(lèi)的繼承

設(shè)計(jì)代碼如下:

    Class dogClass    = [QLDog class];
    Class superClass5 = [dogClass superclass];
    Class superClass6 = [superClass5 superclass];
    Class superClass7 = [superClass6 superclass];
    Class superClass8 = [superClass7 superclass];
    Class superClass9 = [superClass8 superclass];
    
    NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",dogClass,dogClass,superClass5,superClass5,superClass6,superClass6,superClass7,superClass7,superClass8,superClass8,superClass9,superClass9);

打印結(jié)果如下

image.png

由此可得類(lèi)繼承鏈為:QLDog——>QLPerson——>NSObject——>nil

元類(lèi)的繼承

設(shè)計(jì)代碼如下:

    Class metaClass1 = object_getClass(dogClass);
    Class metaClass2 = class_getSuperclass(metaClass1);
    Class metaClass3 = class_getSuperclass(metaClass2);
    Class metaClass4 = class_getSuperclass(metaClass3);
    Class metaClass5 = class_getSuperclass(metaClass4);
    Class metaClass6 = class_getSuperclass(metaClass5);
    
    NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",metaClass1,metaClass1,metaClass2,metaClass2,metaClass3,metaClass3,metaClass4,metaClass4,metaClass5,metaClass5,metaClass6,metaClass6);

打印結(jié)果如下:
image.png

由此可得元類(lèi)繼承鏈為:QLDog——>QLPerson——>NSObject——>NSObject——>nil注意此處兩個(gè)NSObject地址不一樣。

NSObject特殊情況

設(shè)計(jì)代碼如下:

    //NSObject實(shí)例對(duì)象
    NSObject *object1 = [NSObject alloc];
    //NSObject類(lèi)
    Class objClass = object_getClass(object1);
    //NSObject元類(lèi)
    Class objMetaClass = object_getClass(objClass);
    //NSObject根元類(lèi)
    Class rootMetaClass = object_getClass(objMetaClass);
    //NSObject根元類(lèi)的根元類(lèi)
    Class rootRootMetaClass = object_getClass(rootMetaClass);
    
    NSLog(@"\n%@--%p 實(shí)例對(duì)象 \n%@--%p 類(lèi) \n%@--%p 元類(lèi) \n%@--%p 根元類(lèi) \n%@--%p 根根元類(lèi) ",object1,object1,objClass,objClass,objMetaClass,objMetaClass,rootMetaClass,rootMetaClass,rootRootMetaClass,rootRootMetaClass);


    // NSObject根類(lèi)獲取父類(lèi)
    Class objectSuperClass = class_getSuperclass(objClass);
    NSLog(@"%@---%p",objectSuperClass,objectSuperClass);
    
    // NSObject根元類(lèi)獲取父類(lèi)
    Class objectSuperMetaClass = class_getSuperclass(objMetaClass);
    NSLog(@"%@---%p",objectSuperMetaClass,objectSuperMetaClass);

打印結(jié)果如下:

image.png

測(cè)試結(jié)果可得結(jié)論:
1、根類(lèi)父類(lèi)為nil
2、根元類(lèi)父類(lèi)為 NSObject類(lèi)
3、所以萬(wàn)物皆來(lái)自NSObject

繼承圖:箭頭為superclass

image.png

總結(jié)

綜合isa走位鏈以及類(lèi)的繼承鏈,我們引入蘋(píng)果官方的isa/superclass鏈圖


image.png

ps:我的疑問(wèn)以及庫(kù)某人解答如下:
image.png

2021年06月21日16:09:39
——杭州

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

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

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