一個objc對象如何進行內(nèi)存布局?
所有父類的成員變量和自己的成員變量都會存放在該對象所對應(yīng)的存儲空間中.
| Objective-C 對象的結(jié)構(gòu)圖 | |
|---|---|
| ISA指針 | |
| 根類的實例變量 | |
| 倒數(shù)第二層父類的實例變量 | |
| ... | |
| 父類的實例變量 | |
| 類的實例變量 |
根對象就是NSObject,它的superclass指針指向nil
類對象既然稱為對象,那它也是一個實例。類對象中也有一個isa指針指向它的元類(meta class),即類對象是元類的實例。元類內(nèi)部存放的是類方法列表,根元類的isa指針指向自己,superclass指針指向NSObject類。
什么是Class?
每一個對象內(nèi)部都有一個isa指針,指向他的類對象,類對象中存放著本對象的
- 對象方法列表(對象能夠接收的消息列表,保存在它所對應(yīng)的類對象中)
- 成員變量的列表,
- 屬性列表,
Class類的源碼:
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;//isa指針指向Meta Class,因為Objc的類的本身也是一個Object,為了處理這個關(guān)系,runtime就創(chuàng)造了Meta Class,當給類發(fā)送[NSObject alloc]這樣消息時,實際上是把這個消息發(fā)給了Class Object
};
struct objc_class : objc_object {
// Class ISA;
Class superclass;// 父類
cache_t cache; // formerly cache pointer and vtable
//方法緩存,對象接到一個消息會根據(jù)isa指針查找消息對象,這時會在method Lists中遍歷,如果cache了,常用的方法調(diào)用時就能夠提高調(diào)用的效率。
// bits & FAST_DATA_MASK = class_rw_t 獲取具體類信息
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
.
.
.
}
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;//class只讀列表
method_array_t methods;//方法列表
property_array_t properties;//屬性列表
protocol_array_t protocols;//協(xié)議列表
.
.
.
}
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;//instance對象暫用的內(nèi)存大小
#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_ro_t結(jié)構(gòu)體一般保存的是原本類編譯完存在的最原始的類信息,所以為只讀的。class_rw_t結(jié)構(gòu)體也是保存的類信息,但如果在程序運行過程中對類的methods(方法列表)、properties(屬性列表)、protocols(協(xié)議列表)等進行更改時,則是在class_rw_t結(jié)構(gòu)體上進行的。如給類添加分類
獲取類對象和元類的方法:
Class objc_getClass(const char *aClassName)
傳入字符串類名,返回對應(yīng)的類對象
#import <objc/runtime.h>
const char * name = "Student";
Class c = objc_getClass(name);
2.Class object_getClass(id obj)
傳入的obj可能是instance對象、class對象、meta-class對象
返回值 :
如果是instance對象,返回class對象
如果是class對象,返回meta-class對象
如果是meta-class對象,返回NSObject(基類)的meta-class對象
#import <objc/runtime.h>
Class objectClass = [NSObject class];
// 將類對象當做參數(shù)傳入,獲得元類對象
Class objectMetaClass = object_getClass(objectClass);
- (Class)class、+ (Class)class
返回的是類對象
- (Class) {
return self->isa;
}
+ (Class) {
return self;
}
Meta Class本身也是一個Class,它跟其他Class一樣也有自己的 isa 和 super_class 指針??聪聢D:

- 每個Class都有一個isa指針指向一個唯一的Meta Class
Class(
struct objc_class)的isa指針向的地址值與ISA_MASK進行或運算后才為實際元類的地址值
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
每一個Meta Class的isa指針都指向最上層的Meta Class(圖中的NSObject的Meta Class)
最上層的Meta Class的isa指針指向自己,形成一個回路
每一個Meta Class的super class指針指向它原本Class的 Super Class的Meta Class。但是最上層的Meta Class的 Super Class指向NSObject Class本身
instance調(diào)用對象方法的軌跡
isa找到class,方法不存在,就通過superclass找父類class調(diào)用類方法的軌跡
isa找meta-class,方法不存在,就通過superclass找父類
參考: