一. objc_object結構體 objc_class結構體
1.1 objc_object結構體
- isa指針分為
指針型isa
和非指針型isa
1.2 objc_class結構體
結構體主要內(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();
}
......
}
1.3 cache_t結構體
struct cache_t {
struct bucket_t *_buckets;//可以理解為一個數(shù)組
mask_t _mask;
mask_t _occupied;
......
}
cache_t的特點:
1.用于快速
查找方法執(zhí)行函數(shù)
2.是可增量擴展
的哈希表
結構(增量拓展:結構的量增大,內(nèi)存也會增大)
3.是局部性原理
的最佳應用(局部性原理:調(diào)用次數(shù)較高的方法)
1.4 class_data_bits_t結構體
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;
}
};
- 一個類定義的變量 方法 屬性都在class_data_bits_t這個成員結構內(nèi)
protocols(協(xié)議) properties(屬性) methods(方法) 是一個二維數(shù)組,還包括一些分類等
name 類名
ivars 聲明,定義的成員變量
properties 屬性
protocols 協(xié)議
methods 方法
他們是一個一維數(shù)組
二.類對象 元類對象
類對象
存儲實例方法列表等信息
元類對象
存儲類方法列表等信息
問題1:
類對象和元類對象之間有什么區(qū)別和聯(lián)系?
實例對象通過isa指針找到類對象
類對象當中存儲方法列表等信息
類對象通過isa指針找到元類對象、從而可以訪問類方法列表等相關信息
類對象和元類對象都是objc_class數(shù)據(jù)結構,因為繼承objc_object。所以他們才有isa指針,進而可以實現(xiàn)實例對象通過isa指針找到類對象,進而可以訪問實例方法列表等信息。類對象通過isa指針找到元類對象、從而可以訪問類方法列表的相關信息。
問題2:
如果我們調(diào)用的類方法,沒有對應的實現(xiàn)。但是有同名的實例方法,會不會發(fā)生崩潰,會不會產(chǎn)生實際的調(diào)用?
由于根元類對象的superclass指針,指向了根類對象,當我們在元類對象當中查找類方法列表查不到的時候。會順著指針去實例方法列表查找。如果有同名方法,就會調(diào)用同名方法的實例方法調(diào)用。
問題3:
實例方法的傳遞過程?
系統(tǒng)根據(jù)當前的isa指針。找到它的類對象,在它的類對象當中查找方法列表。沒有查找到的話,就會根據(jù)superclass查找父類的類對象的方法列表。然后根類對象的方法列表,如果還沒有,就進入消息轉發(fā)流程。
問題4:
類方法的傳遞過程?
通過類對象的isa指針,找到元類對象。在它的元類對象當中查找方法列表。沒有查找到的話,就會根據(jù)superclass查找父類的元類對象的方法列表。然后順次遍歷方法列表,直到根元類對象,再到根類對象。然后根類對象的方法列表,如果還沒有,就進入消息轉發(fā)流程。
問題4:
類對象 元類對象isa指向問題。
元類對象的isa指針 指向 根元類對象
根元類對象isa指針 指向 根元類對象
根元類對象的superclass指針指向根類對象
問題5:
打印結果
結果都是Phone。因為接收者都是當前對象。
問題6:
消息傳遞的機制?
首先通過 哈希查找 查找緩存,緩存沒命中,查當前類的方法列表是否命中(對于已排序好的列表,采用二分查找,對于沒有排序的列表,采用一般遍歷查找方法)。如果仍然沒命中,逐級父類方法列表是否命中(父類查找是先通過superclass指針查找父類,遍歷每一個父類,對于每一個父類,又通過緩存查找和當前類方法列表查找)。如果都沒有命中,進入消息轉發(fā)流程。
問題7:
[obj foo]和objc_msgSend()函數(shù)之間有什么關系?
編譯之后,會在內(nèi)部變成objc_msgSend()函數(shù)調(diào)用。
問題8:
消息轉發(fā)流程3個步驟
1.resolvelnstanceMethod(告訴系統(tǒng)是否要解決當前的方法實現(xiàn))
2.forwardingTargetForSelector:(告訴系統(tǒng)這個實例方法的調(diào)用應該由哪個對象來處理,轉發(fā)對象是誰)
3.methodSignatureForSelector:(1.返回方法簽名,調(diào)用forwardInvocation,如果可以處理,轉發(fā)結束 2.如果返回為nil,或者forwardInvocation無法處理,無法找到方法崩潰)
問題9:
runtime如何通過Selector找到對應的IMP地址的?
首先查找當前實例對應類對象的緩存是否有Selector對應的IMP實現(xiàn),如果緩存命中,就把命中的緩存函數(shù)返回給調(diào)用方。如果緩存沒有命中。根據(jù)當前類的方法列表查找Selector對應的IMP事件。當前類如果沒有命中,再根據(jù)當前類的superClass指針逐級查找父類的方法列表。然后查找Selector對應的IMP事件。
問題10:
@dynamic (動態(tài)方法解析)
相當于在運行時添加set get方法。而不是在編譯時聲明好
動態(tài)運行時語言將函數(shù)決議推遲到運行時
編譯時語言在編譯期進行函數(shù)決議