以前只是看了很多博客锐锣,這次打算看一下源碼腌闯,并記錄下來。想到哪里就讀到哪里雕憔,寫到哪里姿骏。讀的代碼版本是:
objc runtime 680
,可以從這里下載
對象和類
首先在 objc-private.h
文件中可以看到objc_object
結構體,這就是對對象的定義
struct objc_object {
private:
isa_t isa;
}
在objc-runtime-new.h
中可以看到objc_class
結構體斤彼,這就是對類的定義分瘦,因為它繼承了objc_object
,所以我把isa
變量也加入到objc_class
中來琉苇。
struct objc_class : objc_object {
isa_t isa;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
}
superclass
指向該類的父類嘲玫,NSObject
的父類指向NULL
Cache
cache
主要用于方法性能優(yōu)化,如果每發(fā)送一個消息都需要去方法表中去查找并扇,當方法很多的時候去团,查找是很耗力的,并且當 存在繼承關系的時候穷蛹,一個方法的查找鏈可能會很長渗勘。那么對使用過的方法進行緩存,便于第二次查找俩莽,這樣節(jié)省的時間也是非惩梗可觀的。
來看一下cache_t
的具體代碼扮超,在objc-runtime-new.h
的第52行可以看到
struct cache_t {
struct bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
}
-
mask
:分配用來緩存bucket
的總數(shù) -
occupied
:表明目前實際占用的緩存bucket
的個數(shù) -
_buckets
:一個散列表取刃,用來方法緩存,bucket_t
類型出刷,包含key
以及方法實現(xiàn)IMP
struct bucket_t {
private:
cache_key_t _key;
IMP _imp;
}
class_data_bits_t
在objc-runtime-new.h
的 817 行可以看到結構體中只有一個bits
屬性來存儲類信息
struct class_data_bits_t {
// Values are the FAST_ flags above.
uintptr_t bits;
}
還有objc_class
有注釋說
// class_rw_t * plus custom rr/alloc flags
那我們看一下class_rw_t
到底是什么璧疗,在objc-runtime-new.h
的778行可以看到
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;
}
Objc
的類的屬性、方法馁龟、以及遵循的協(xié)議都放在class_rw_t
中崩侠,下面對其中幾個關鍵詞進行分析
class_ro_t
ro
是一個指向常量的指針,存儲來編譯器決定了的屬性坷檩、方法和遵守協(xié)議
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;
}
};
Method
Method
存儲了方法名却音、類型信息改抡、方法實現(xiàn)
struct method_t {
SEL name;
const char *types;
IMP imp;
}
iVar
ivar
代表類中的實例變量
struct ivar_t {
#if __x86_64__
// *offset was originally 64-bit on some x86_64 platforms.
// We read and write only 32 bits of it.
// Some metadata provides all 64 bits. This is harmless for unsigned
// little-endian values.
// Some code uses all 64 bits. class_addIvar() over-allocates the
// offset for their benefit.
#endif
int32_t *offset;
const char *name;
const char *type;
// alignment is sometimes -1; use alignment() instead
uint32_t alignment_raw;
uint32_t size;
uint32_t alignment() const {
if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT;
return 1 << alignment_raw;
}
};
說起來實例變量,就想到了對象的內(nèi)存結構系瓢,為了搞清楚阿纤,也做了一個測試,Person
繼承于People
夷陋,People
繼承于NSObject
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
// 此處打斷點
}
}
在注釋處打斷點欠拾,然后在 Console
中輸入p *person
,查看輸出結果骗绕,對象中會包含一個isa指針藐窄、類的實例變量,以及父類的實例變量
(lldb) p *person
(Person) $0 = {
People = {
NSObject = {
isa = Person
}
_name = nil
}
_age = nil
}
(lldb)
如果有理解錯誤酬土,望留言告知