iOS runtime詳細(xì)內(nèi)容

runtime的主要數(shù)據(jù)結(jié)構(gòu).png

一. objc_object結(jié)構(gòu)體 objc_class結(jié)構(gòu)體

1.1 objc_object結(jié)構(gòu)體
image.png
image1.png
  • isa指針分為 指針型isa非指針型isa
image.png
1.2 objc_class結(jié)構(gòu)體
結(jié)構(gòu)體主要內(nèi)容:
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    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() { 
        return bits.data();
    }
    ......
}
image.png
1.3 cache_t結(jié)構(gòu)體
struct cache_t {
    struct bucket_t *_buckets;//可以理解為一個(gè)數(shù)組
    mask_t _mask;
    mask_t _occupied;
    ......
}
方法緩存的數(shù)據(jù)結(jié)構(gòu).png
通過哈希查找.png
image.png

cache_t的特點(diǎn):
1.用于快速查找方法執(zhí)行函數(shù)
2.是可增量擴(kuò)展哈希表結(jié)構(gòu)(增量拓展:結(jié)構(gòu)的量增大,內(nèi)存也會(huì)增大)
3.是局部性原理的最佳應(yīng)用(局部性原理:調(diào)用次數(shù)較高的方法)

1.4 class_data_bits_t結(jié)構(gòu)體

class_data_bits_t包含class_rw_t,class_rw_t內(nèi)包含

struct class_rw_t {
    uint32_t flags;
    uint32_t version;

    const class_ro_t *ro;

    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;

    Class firstSubclass;
    Class nextSiblingClass;

    char *demangledName;
    ......
}
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name;
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};
image.png
  • 一個(gè)類定義的變量 方法 屬性都在class_data_bits_t這個(gè)成員結(jié)構(gòu)內(nèi)
image.png

protocols(協(xié)議) properties(屬性) methods(方法) 是一個(gè)二維數(shù)組,還包括一些分類等

image.png

name 類名
ivars 聲明,定義的成員變量
properties 屬性
protocols 協(xié)議
methods 方法
他們是一個(gè)一維數(shù)組

image.png
image.png

二.類對(duì)象 元類對(duì)象

類對(duì)象 存儲(chǔ)實(shí)例方法列表等信息
元類對(duì)象 存儲(chǔ)類方法列表等信息

image.png

問題1:類對(duì)象和元類對(duì)象之間有什么區(qū)別和聯(lián)系?

實(shí)例對(duì)象通過isa指針找到類對(duì)象
類對(duì)象當(dāng)中存儲(chǔ)方法列表等信息
類對(duì)象通過isa指針找到元類對(duì)象、從而可以訪問類方法列表等相關(guān)信息
類對(duì)象和元類對(duì)象都是objc_class數(shù)據(jù)結(jié)構(gòu),因?yàn)槔^承objc_object。所以他們才有isa指針,進(jìn)而可以實(shí)現(xiàn)實(shí)例對(duì)象通過isa指針找到類對(duì)象,進(jìn)而可以訪問實(shí)例方法列表等信息。類對(duì)象通過isa指針找到元類對(duì)象、從而可以訪問類方法列表的相關(guān)信息。

問題2:如果我們調(diào)用的類方法,沒有對(duì)應(yīng)的實(shí)現(xiàn)。但是有同名的實(shí)例方法,會(huì)不會(huì)發(fā)生崩潰,會(huì)不會(huì)產(chǎn)生實(shí)際的調(diào)用?

由于根元類對(duì)象的superclass指針,指向了根類對(duì)象,當(dāng)我們?cè)谠悓?duì)象當(dāng)中查找類方法列表查不到的時(shí)候。會(huì)順著指針去實(shí)例方法列表查找。如果有同名方法,就會(huì)調(diào)用同名方法的實(shí)例方法調(diào)用。

問題3:實(shí)例方法的傳遞過程?

系統(tǒng)根據(jù)當(dāng)前的isa指針。找到它的類對(duì)象,在它的類對(duì)象當(dāng)中查找方法列表。沒有查找到的話,就會(huì)根據(jù)superclass查找父類的類對(duì)象的方法列表。然后根類對(duì)象的方法列表,如果還沒有,就進(jìn)入消息轉(zhuǎn)發(fā)流程。

問題4:類方法的傳遞過程?

通過類對(duì)象的isa指針,找到元類對(duì)象。在它的元類對(duì)象當(dāng)中查找方法列表。沒有查找到的話,就會(huì)根據(jù)superclass查找父類的元類對(duì)象的方法列表。然后順次遍歷方法列表,直到根元類對(duì)象,再到根類對(duì)象。然后根類對(duì)象的方法列表,如果還沒有,就進(jìn)入消息轉(zhuǎn)發(fā)流程。

問題4:類對(duì)象 元類對(duì)象isa指向問題。

元類對(duì)象的isa指針 指向 根元類對(duì)象
根元類對(duì)象isa指針 指向 根元類對(duì)象
根元類對(duì)象的superclass指針指向根類對(duì)象

問題5:打印結(jié)果

image.png

結(jié)果都是Phone。因?yàn)榻邮照叨际钱?dāng)前對(duì)象。


image.png

問題6:消息傳遞的機(jī)制?
首先通過 哈希查找 查找緩存,緩存沒命中,查當(dāng)前類的方法列表是否命中(對(duì)于已排序好的列表,采用二分查找,對(duì)于沒有排序的列表,采用一般遍歷查找方法)。如果仍然沒命中,逐級(jí)父類方法列表是否命中(父類查找是先通過superclass指針查找父類,遍歷每一個(gè)父類,對(duì)于每一個(gè)父類,又通過緩存查找和當(dāng)前類方法列表查找)。如果都沒有命中,進(jìn)入消息轉(zhuǎn)發(fā)流程。

image.png

問題7:[obj foo]和objc_msgSend()函數(shù)之間有什么關(guān)系?
編譯之后,會(huì)在內(nèi)部變成objc_msgSend()函數(shù)調(diào)用。

問題8:消息轉(zhuǎn)發(fā)流程3個(gè)步驟
1.resolvelnstanceMethod(告訴系統(tǒng)是否要解決當(dāng)前的方法實(shí)現(xiàn))
2.forwardingTargetForSelector:(告訴系統(tǒng)這個(gè)實(shí)例方法的調(diào)用應(yīng)該由哪個(gè)對(duì)象來處理,轉(zhuǎn)發(fā)對(duì)象是誰)
3.methodSignatureForSelector:(1.返回方法簽名,調(diào)用forwardInvocation,如果可以處理,轉(zhuǎn)發(fā)結(jié)束 2.如果返回為nil,或者forwardInvocation無法處理,無法找到方法崩潰)

image.png

問題9:runtime如何通過Selector找到對(duì)應(yīng)的IMP地址的?
首先查找當(dāng)前實(shí)例對(duì)應(yīng)類對(duì)象的緩存是否有Selector對(duì)應(yīng)的IMP實(shí)現(xiàn),如果緩存命中,就把命中的緩存函數(shù)返回給調(diào)用方。如果緩存沒有命中。根據(jù)當(dāng)前類的方法列表查找Selector對(duì)應(yīng)的IMP事件。當(dāng)前類如果沒有命中,再根據(jù)當(dāng)前類的superClass指針逐級(jí)查找父類的方法列表。然后查找Selector對(duì)應(yīng)的IMP事件。

問題10:@dynamic (動(dòng)態(tài)方法解析)
相當(dāng)于在運(yùn)行時(shí)添加set get方法。而不是在編譯時(shí)聲明好

動(dòng)態(tài)運(yùn)行時(shí)語言將函數(shù)決議推遲到運(yùn)行時(shí)
編譯時(shí)語言在編譯期進(jìn)行函數(shù)決議

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

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