导语:通过浅谈系列的第一篇,了解OC对象,类,元类的一些基本情况,今天我们开始了解一下类对象,元类对象的结构。下一个阶段探讨OC的消息机制,了解了类和元类的结构有助于快速理解消息机制在发送消息阶段是如何查找方法的。
isa指针
- 从64bit开始,isa并不是直接储存指针,而是储存了非常多信息。
要获得isa里存class,meta-class地址的指针,需要进行一下位运算才行
isa & ISA_MASK。
本篇重点是探讨类和元类的结构,关于isa就不多说了。
class 、meta-class
- class、meta-class的结构是
struct objc_class
类对象,元类对象本质就是结构体,并且类和元类的结构都是一样的。只是存储的信息不一样。
struct objc_class {
Class isa;
Class superclass;
cache_t cache;
class_data_bits_t bits;
};
struct objc_class | 说明 |
|---|---|
| isa | 类的isa指向元类对象(元类的isa直接指向基类的元类对象) |
| superclass | 类的superclass就指向父类,元类的superclass指向父类的元类 |
| cache | 方法缓存(方法调用会先在此处查找) |
| bits | & FAST_DATA_MASK 与运算,可以找到class_rw_t结构体 |
class_rw_t:通过查看源码,class_rw_t简化之后得出以下内容:
struct class_rw_t{
...
const class_ro_t *ro;
const method_array_t methods;
const property_array_t properties;
const protocol_array_t protocols;
...
}
struct class_rw_t | 说明 |
|---|---|
| ro | ro结构体重包含了一些类的信息(instance对象占用的内存,类名,成员列表) |
| methods | 方法列表 |
| properties | 属性列表 |
| protocols | 协议列表 |
struct class_ro_t:通过查看源码,class_ro_t简化之后得出以下内容:
struct class_ro_t{
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
union {
const uint8_t * ivarLayout;
Class nonMetaclass;
};
char * name;
void *baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
}
struct class_ro_t | 说明 |
|---|---|
| instanceSize | instance对象所占用的内存 |
| name | 类名 |
| baseMethodList | 基本方法列表 |
| baseProtocols | 基本协议列表 |
| ivars | 成员列表 |
| baseProperties | 基本属性列表 |
class_rw_t与class_ro_t都有方法列表,协议列表,属性列表。那么有什么不同呢?
简单来说,
class_ro_t是只读内存区,里面的所有数据初始化之后都是不可更改的,方法列表,协议列表,属性列表,成员变量列表都是类的最原始并且不可更改的数据。
class_rw_t是可读写内存区,后期加入的可更改的数据都在此处,分类(category)中扩展的数据会在runtime运行期加入到class_rw_t。
总结:
-
objc_class结构体的bits & FAST_DATA_MASK可以获取class_rw_t,class_ro_t又是class_rw_t里的一个成员。 -
对象的成员变量,对象方法,协议,属性这些数据都保存到类对象里面,类方法在元类对象里。 (如果有一定c,c++基础,可以仿照苹果官方的代码,写出一个objc_class结构体进行调试)