class_ro_t
class_ro_t
存储了当前类在编译期就已经确定的属性
、方法
以及遵循的协议
,里面是没有分类的方法的。那些运行时添加的方法将会存储在运行时生成的class_rw_t
中。
ro
即表示read only
,是无法进行修改的。
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;
}
};
class_rw_t
ObjC
类中的属性、方法还有遵循的协议等信息都保存在 class_rw_t
中:
// 可读可写
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; // 指向只读的结构体,存放类初始信息
/*
这三个都是二位数组,是可读可写的,包含了类的初始内容、分类的内容。
methods中,存储 method_list_t ----> method_t
二维数组,method_list_t --> method_t
这三个二位数组中的数据有一部分是从class_ro_t中合并过来的。
*/
method_array_t methods; // 方法列表(类对象存放对象方法,元类对象存放类方法)
property_array_t properties; // 属性列表
protocol_array_t protocols; //协议列表
Class firstSubclass;
Class nextSiblingClass;
//...
}
class_rw_t生成时机
class_rw_t
生成在运行时,在编译期间,class_ro_t
结构体就已经确定,objc_class
中的bits
的data部分存放着该结构体的地址。在runtime
运行之后,具体说来是在运行runtime
的realizeClass
方法时,会生成class_rw_t
结构体,该结构体包含了class_ro_t
,并且更新data部分,换成class_rw_t
结构体的地址。
类的realizeClass
运行之前:
类的realizeClass
运行之后:
细看两个结构体的成员变量会发现很多相同的地方,他们都存放着当前类的属性、实例变量、方法、协议等等。区别在于:class_ro_t
存放的是编译期间就确定的;而class_rw_t
是在runtime时才确定,它会先将class_ro_t
的内容拷贝过去,然后再将当前类的分类的这些属性、方法等拷贝到其中。所以可以说class_rw_t
是class_ro_t
的超集,当然实际访问类的方法、属性等也都是访问的class_rw_t
中的内容
分类方法加载到class_rw_t的流程
- 程序启动后,通过编译之后,
Runtime
会进行初始化,调用_objc_init
。
_objc_init
由dyld
驱动,这个阶段会注册3
个回调,分别是mapped
,init
,unmapped
/***********************************************************************
* _objc_init
* Bootstrap initialization. Registers our image notifier with dyld.
* Called by libSystem BEFORE library initialization time
**********************************************************************/
void _objc_init(void)
{
static bool initialized = false;