1悟泵、什么是類
iOS中所以的類繼承NSObject猪叙,那么在底層NSObject的結(jié)構(gòu)是怎么樣的呢浅碾?
使用clang編譯一下如下代碼
#import <Foundation/Foundation.h>
@interface MCPerson : NSObject
@property (nonatomic,copy) NSString *name;
@end
@implementation MCPerson
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
MCPerson *p = [MCPerson alloc];
p.name = @"Hello";
}
return 0;
}
編譯命令
clang -rewrite-objc main.m
生成文件main.cpp,搜索找到相關(guān)代碼
struct objc_object {
Class _Nonnull isa __attribute__((deprecated));
};
struct objc_class : objc_object {...};//在objc-runtime-new源碼中
typedef struct objc_object *id;//在objc-runtime-new源碼中
typedef struct objc_class *Class;//結(jié)構(gòu)體指針
typedef struct objc_object NSObject;//NSObject在底層是一個(gè)結(jié)構(gòu)體里面包含isa指針
剛好證明OC中的萬(wàn)物皆對(duì)象原則影暴,所以派生類都繼承NSObject,在底層都繼承objc_object結(jié)構(gòu)體腻豌,簡(jiǎn)單來(lái)說(shuō)家坎,類的底層是繼承objc_object,包含isa吝梅、superclass虱疏、cache、bits的結(jié)構(gòu)體
2苏携、類的結(jié)構(gòu)
objc_class源碼
struct objc_class : objc_object {
// Class ISA; //繼承objc_object做瞪,所以有isa指針
Class superclass; //父類
cache_t cache; // 主要是緩存方法
class_data_bits_t bits; // 數(shù)據(jù)存儲(chǔ)
class_rw_t *data() const {
return bits.data();
}
}
-
Class isa 指針
在對(duì)象初始化的時(shí)候通過(guò)isa將對(duì)象和類關(guān)聯(lián)起來(lái),而類也是一個(gè)對(duì)象右冻,俗稱類對(duì)象装蓬,類對(duì)象也是需要和元類關(guān)聯(lián)起來(lái)的著拭,所以類中也有isa指針。
isa走位圖
Class superclass
這個(gè)很好理解矛物,就是父類茫死,一般來(lái)說(shuō),大部分類的父類都是NSObject履羞,根元類的父類也是NSObject峦萎,NSObject的父類是nil。cache_t cache
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
explicit_atomic<struct bucket_t *> _buckets;
explicit_atomic<mask_t> _mask;
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
explicit_atomic<uintptr_t> _maskAndBuckets;
mask_t _mask_unused;
...
};
感覺(jué)這個(gè)成員變量的作用主要是用來(lái)緩存方法忆首,留個(gè)疑問(wèn)爱榔。
- class_data_bits_t bits
struct class_data_bits_t {
friend objc_class;
// Values are the FAST_ flags above.
uintptr_t bits;
class_rw_t* data() const {//核心,存儲(chǔ)方法糙及、屬性详幽、協(xié)議,可以動(dòng)態(tài)修改
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
const class_ro_t *safe_ro() {//存儲(chǔ)成員變量浸锨,不可動(dòng)態(tài)修改唇聘,類似readonly
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;
}
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
bool hasCustomRR() const {
return !bits.getBit(FAST_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
bits.setBits(FAST_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
bits.clearBits(FAST_HAS_DEFAULT_RR);
}
...
};
這里值得我們注意的是,objc_class 的 data()方法其實(shí)是返回的 bits 的 data() 方法柱搜,而通過(guò)這個(gè) data() 方法迟郎,我們發(fā)現(xiàn)諸如類的字節(jié)對(duì)齊、ARC聪蘸、元類等特性都有 data() 的出現(xiàn)宪肖,這間接說(shuō)明 bits 屬性其實(shí)是個(gè)大容器,有關(guān)于內(nèi)存管理健爬、C++ 析構(gòu)等內(nèi)容在其中有定義控乾。
重點(diǎn):
class_rw_t* data() //存儲(chǔ)方法、屬性娜遵、協(xié)議蜕衡,可以動(dòng)態(tài)修改
const class_ro_t *safe_ro() //存儲(chǔ)成員變量,不可動(dòng)態(tài)修改魔熏,類似readonly
3衷咽、類的方法、屬性蒜绽、協(xié)議分別存在哪里
struct class_rw_t {
const class_ro_t *ro() const {//ro
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>()->ro;
}
return v.get<const class_ro_t *>();
}
const method_array_t methods() const {//方法列表
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->methods;
} else {
return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
}
}
const property_array_t properties() const {//屬性列表
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->properties;
} else {
return property_array_t{v.get<const class_ro_t *>()->baseProperties};
}
}
const protocol_array_t protocols() const {//協(xié)議列表
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>()->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
}
}
...
};
4镶骗、如何讀取類中的方法、屬性躲雅、協(xié)議
屬性鼎姊、方法、協(xié)議都存在rw中,所以我們先需要獲取rw
(lldb) p/x MCPerson.class
(Class) $0 = 0x0000000100002180 MCPerson
(lldb) p/x 0x0000000100002180 + 0x20
(long) $1 = 0x00000001000021a0
(lldb) p (class_data_bits_t *)$1
(class_data_bits_t *) $2 = 0x00000001000021a0
(lldb) p (class_rw_t*)$2->data()
(class_rw_t *) $3 = 0x000000010073b800//屬性方法都在這里面
- 獲取方法
(lldb) p $3->methods() //獲取方法
(const method_array_t) $4 = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x00000001000020c0
arrayAndFlag = 4294975680
}
}
}
(lldb) p $4.list
(method_list_t *const) $5 = 0x00000001000020c0
(lldb) p *$5//打印指針的內(nèi)容
(method_list_t) $6 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 3
first = {
name = ".cxx_destruct"
types = 0x0000000100000fa0 "v16@0:8"
imp = 0x0000000100000e50 (KCObjc`-[MCPerson .cxx_destruct] at main.m:16)
}
}
}
(lldb) p $6.get(0)// 獲取第1個(gè)方法
(method_t) $7 = {
name = ".cxx_destruct"
types = 0x0000000100000fa0 "v16@0:8"
imp = 0x0000000100000e50 (KCObjc`-[MCPerson .cxx_destruct] at main.m:16)
(lldb) p $6.get(1)
(method_t) $8 = {
name = "name"
types = 0x0000000100000f8d "@16@0:8"
imp = 0x0000000100000df0 (KCObjc`-[MCPerson name] at main.m:13)
}
(lldb) p $6.get(2)
(method_t) $9 = {
name = "setName:"
types = 0x0000000100000f95 "v24@0:8@16"
imp = 0x0000000100000e20 (KCObjc`-[MCPerson setName:] at main.m:13)
}
- 獲取屬性
(lldb) p $3->properties()//獲取屬性
(const property_array_t) $10 = {
list_array_tt<property_t, property_list_t> = {
= {
list = 0x0000000100002138
arrayAndFlag = 4294975800
}
}
}
(lldb) p $10.list
(property_list_t *const) $11 = 0x0000000100002138
(lldb) p *$11
(property_list_t) $12 = {
entsize_list_tt<property_t, property_list_t, 0> = {
entsizeAndFlags = 16
count = 1
first = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
}
}
(lldb) p $12->get(0)
(property_t) $13 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
Fix-it applied, fixed expression was:
$12.get(0)
(lldb) p $12.get(0)
(property_t) $14 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
- 獲取協(xié)議
(lldb) p $3->protocols()//獲取協(xié)議
(const protocol_array_t) $15 = {
list_array_tt<unsigned long, protocol_list_t> = {
= {
list = 0x0000000000000000//全是0相寇,表明沒(méi)有慰于,如果有跟上面的步驟一致
arrayAndFlag = 0
}
}
}
4、類的成員變量存在哪里
拓展唤衫,成員變量沒(méi)有存在rw中婆赠,存在ro中
5、總結(jié)
萬(wàn)物皆對(duì)象:類的本質(zhì)就是對(duì)象佳励,類也是對(duì)象(類對(duì)象)
類在 class_rw_t 結(jié)構(gòu)中存儲(chǔ)了編譯時(shí)確定的屬性休里、方法和協(xié)議等內(nèi)容。
實(shí)例方法存放在類中赃承,類方法存在元類中