03.02 Runtime objc4-723 objc_class

Runtime objc4-723 objc_class

前情提要:runtime的源碼版本: objc4-723時間:2019-01-06


objc_class

<code>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();
}

...
}/<code>

Class superclass

指向父類的指針

這裡可以聯想到一個經典的問題,isa指向什麼?

複習一下:

Class是objc_object類型,在objc_object中只有一個isa指針

superclass是一個Class類型的指針. 每個實例對象有個isa的指針,他指向對象的類,而Class裡也有個isa的指針, 指向meteClass(元類)。

回憶一個小知識點:實例方法存放在類對象中,類方法存放在類對象的類中,即元類中。

元類保存了類方法的列表。當類方法被調用時,先會從本身查找類方法的實現,如果沒有,元類會向他父類查找該方法。同時注意的是:元類(meteClass)也是類,它也是對象。元類也有isa指針,它的isa指針最終指向的是一個根元類(root meteClass).根元類的isa指針指向本身,這樣形成了一個封閉的內循環。

一張經典的圖片解釋:(圖片為轉載,詳情見水印)


Runtime objc4-723 objc_class


cache_t cache

<code>struct cache_t {
// 緩存數組
struct bucket_t *_buckets;
//
mask_t _mask;
// 佔用大小
mask_t _occupied;
...
}
/<code>

在很多資料裡我們也見過關於類中的方法緩存的介紹,這個cache就是方法緩存的結構。

struct bucket_t *_buckets; 標識它是一個bucket_t為單位的鏈表結構(數組)

<code>struct bucket_t {
private:
//typedef uintptr_t cache_key_t;
cache_key_t _key;
IMP _imp;
...
}
/<code>

不難看出它可以通過key快速的找到Method對應的IMP以實現快速查找。


class_rw_t

與之對應的還有一個class_ro_t,class_rw_t

中包含class_ro_t
class_ro_t 在編譯期產生,它是類中的可讀信息。
class_rw_t 在運行時產生,它是類中的可讀寫信息。

<code>
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
// 標記
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;

// 以上這兩個屬性將某個類的子類串聯成一個列表,所以,我們可以通過class_rw_t 獲取到當前類的所有子類
// superClass.firstSubclass -> subClass1.nextSiblingClass -> subClass2.nextSiblingClass -> ...

char *demangledName;
}
/<code>

class_ro_t

<code>
struct class_ro_t {
uint32_t flags;
// 開始位置
uint32_t instanceStart;
// 所佔空間大小
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
// ivar 佈局, 在編譯期這裡就固定了,它標示ivars的內存佈局,在運行時不能改變,這也是為什麼我們在運行時不能動態給類添加成員變量的原因
const uint8_t * ivarLayout;

// 名字
const char * name;

// 方法列表
method_list_t * baseMethodList;

// 協議列表
protocol_list_t * baseProtocols;

// 成員變量列表
const ivar_list_t * ivars;

// weak 成員變量的內存佈局
const uint8_t * weakIvarLayout;

// 屬性列表
property_list_t *baseProperties;

method_list_t *baseMethods() const {
return baseMethodList;
}
};/<code>

class_data_bits_t bits

<code>class_rw_t *data() { 
return bits.data();
}


// class_data_bits_t data()
class_rw_t* data() {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}/<code>

以及它的結構體實現,可以看出,他是class_rw_t的一個封裝,作用是可以通過它來操作、獲取class_rw_t的信息。

概括一下class的結構


Runtime objc4-723 objc_class


分享到:


相關文章: