類的底層原理探索(上)

Class 的本質(zhì)是 objc_class類型的結(jié)構(gòu)體, objc_class本質(zhì)也是對(duì)象,繼承自objc_object。
objc_class 內(nèi)部也有一個(gè)isa指針。


image.png

類對(duì)象的isa指向分析

我們打印一下對(duì)象的指針來查看一下


image.png

我們將p的指針與上掩碼,得到了類對(duì)象LGPerson,我們通過類對(duì)象的指針與上排碼能得到什么呢?我們發(fā)現(xiàn)類對(duì)象的isa指針也指向LGPerson,同時(shí)2個(gè)LGPerson的內(nèi)存地址不一樣。


image.png

我們發(fā)現(xiàn)對(duì)象isa所指向的LGPerson類的地址為0x00000001000082f0,而LGPerson類中isa所指向的LGPerson地址為0x00000001000082c8,說明這是兩個(gè)不同的類!而且LGPerson的元類也是LGPerson。

到此我們得到了如下結(jié)論
實(shí)例對(duì)象的isa -->類對(duì)象 isa--> 元類對(duì)象
那元類的isa指針指向哪里呢,我們接著看

image.png

通過打印看到,元類的指針指向根元類

那么根元類的isa又指向哪里呢?


image.png

通過打印根元類的內(nèi)存空間,發(fā)現(xiàn)根元類的isa指向了自己。

總結(jié)如圖

image.png

類與元類的繼承關(guān)系

先說結(jié)論:元類的父類就是父類的元類

image.png

在進(jìn)行superclass走位分析之前,先要確定superclass指針?biāo)谖恢?,查看objc_class源碼實(shí)現(xiàn):

struct objc_class : objc_object {
    // Class ISA;
    Class superclass; // 第二個(gè)8字節(jié)
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const {
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }
    
    …… 省略
}

通過上面的源碼可以確定,superclass指針在類的第二個(gè)8字節(jié)中。


image.png

繼續(xù)打印LGperson的父類


image.png

通過打印發(fā)現(xiàn)LGPerson的父類指向NSObject

繼續(xù) 查找NSObject的父類


image.png

通過驗(yàn)證可以確定,NSObject的isa 指向自己 , NSObject的父類是nil。

總結(jié)如圖


image.png

那有沒有想過蘋果為什么要設(shè)計(jì)元類呢?這個(gè)我們放在后面講,這邊我們先看一下objc_class里存放了什么東西

通過內(nèi)存平移訪問bits數(shù)據(jù)

內(nèi)存平移

image.png

如圖中所示,p是個(gè)指針,指向了整形數(shù)組的首地址c,d+1則表示指針平移int類型大小的字節(jié),即就是平移4個(gè)字節(jié),也就是數(shù)組第一個(gè)元素的地址,以此類推。

好了,知道了什么是內(nèi)存平移,我們來對(duì)這個(gè)bits進(jìn)行探究。我們定義一個(gè)Person類,

image.png

運(yùn)行程序,并且在main函數(shù)中打上斷點(diǎn),先輸出Person類對(duì)象的地址分布,參考源碼中objc_class的結(jié)構(gòu)(全局搜索struct objc_class),要拿到bits,需要內(nèi)存平移32位,也就是說0x1000081b8就是我們要操作的地址。我們將該地址進(jìn)行強(qiáng)轉(zhuǎn)為class_data_bits_t得到一個(gè)地址,我們通過對(duì)地址進(jìn)行取值,得到的結(jié)果對(duì)我們并沒有什么參考意義,怎么辦呢?
image.png

結(jié)果返回的class_data_bits_t類型我們可以試著對(duì)其進(jìn)行探索,跳轉(zhuǎn)到其定義處:

struct class_data_bits_t {
    friend objc_class;
    // Values are the FAST_ flags above.
    uintptr_t bits;
public:
    // !!重點(diǎn)--獲取class_rw_t!!
    class_rw_t* data() const {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
    ...
    // !!重點(diǎn)--獲取class_ro_t!!
    const class_ro_t *safe_ro() const {
        class_rw_t *maybe_rw = data();
        if (maybe_rw->flags & RW_REALIZED) {
            // maybe_rw is rw
            return maybe_rw->ro();
        } else {
            // maybe_rw is actually ro
            return (class_ro_t *)maybe_rw;
        }
    }

發(fā)現(xiàn)其有個(gè)叫做class_rw_t* data()的方法,我們試著對(duì)其進(jìn)行調(diào)用并得到的地址進(jìn)行取值:


image.png

好像沒什么對(duì)我們有用的信息,這時(shí)候我們就跳轉(zhuǎn)到class_rw_t類型的定義處,發(fā)現(xiàn)里面有很多方法,我們發(fā)現(xiàn)了幾個(gè)很熟悉的方法:methods,properties,protocols等等。我們試著對(duì)其進(jìn)行調(diào)用,里面有個(gè)list,我們繼續(xù)對(duì)其進(jìn)行解析,得到一個(gè)method_list_t類型的地址,并對(duì)其取值。


image.png

image.png

上面的輸出信息里有個(gè)count,我們猜測是實(shí)例方法的個(gè)數(shù),我們定義的類中有兩個(gè)屬性,setter和getter方法加起來有4個(gè),再加上定義的一個(gè)instanceMethod方法,總共有5個(gè),可是這個(gè)count卻有6個(gè)。別急,我們接著往下看。

我們查看method_list_t的定義,沒找到有用的信息,去entsize_list_tt里面找:

image.png

image.png

這個(gè)get方法應(yīng)該就是獲取method的方法,給其傳下標(biāo)即可。我們可以試下,發(fā)現(xiàn)其輸出結(jié)果并不是我們預(yù)想的那樣。

image.png

那我們接著對(duì)method_t類型進(jìn)行探索,跳轉(zhuǎn)到其定義處,發(fā)現(xiàn)其有一個(gè)getDescription方法:


image.png

我們試著對(duì)其進(jìn)行調(diào)用并對(duì)所得地址進(jìn)行取值:

image.png

我們成功拿到了方法名以及參數(shù)列表。如法炮制,對(duì)剩下的五個(gè)方法進(jìn)行打?。?/p>

image.png

原來多出的那個(gè)方法是這個(gè)叫.cxx_destruct的方法,猜測是反初始化方法。

我們也可以通過上面的探索的方式獲取屬性列表。

所以類對(duì)象中存儲(chǔ)了實(shí)例方法列表,屬性列表以及協(xié)議方法列表以及cache和指向元類的指針以及指向父類的指針。

最后編輯于
?著作權(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)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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