Class 深入分析
主题 1 : Class结构分析
class结构:
struct objc_class : objc_object { // objc_object 内包含 isa
// Class ISA;
Class superclass; // 父类,元类对象
cache_t cache; // 缓存表
class_data_bits_t bits; // class_rw_t内部用来获取基础信息的标记
class_rw_t *data() { // 可读可写结构:方法,属性,协议 ,对象信息 等
都整合到此处
return bits.data();
}
...
}
预告:class_rw_t
class_rw_t
OC类的方法、属性、协议都是可以动态添加,也就是可读可写的,从结构名可见
一斑
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;
}
class_ro_t *ro 结构中ro应该是存储只读属性的结构
预告:class_ro_t
class_ro_t *ro
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize; //instance对象占用的内存空间
#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;
}
};
明显 类名 和 成员变量 是不可变的。const 修饰
成员变量信息ivars 是被const修饰说明是不可修改的,这也就是为什么Runtime
无法动态增加成员变量,底层结构决定的。
疑问
为什么class_rw_t 同内部 class_ro_t *ro 都有方法、属性、协议 ? 是否一样?
1.开始初始化定义class结构时 没有class_rw_t结构,只有 class_ro_t ,也就是
只读
记录类 @interface和@end之间的方法,属性,等信息
2.接着分配空间给读写信息,也就是rw,在准备处理category信息的加载之前
原来的ro指向新结构的rt.ro
3.在有了class_rw_t之后,便会进行category的处理,将Class本身的方法列表
和category里面的方法列表先后放到class_rw_t的method_array_t methods里
面,Class自身的方法列表会被最先放入其中,并且置于列表的尾部,category
方法列表的加入顺序等同与category文件参与编译的顺序
只有rt内的列表发生变化,ro还是初始化时的样子
预告:method_t
method_t
方法/函数
struct method_t {
SEL name; // SEL是方法选择器
const char *types; // 函数类型编码(包括返回值类型、参数类型)
IMP imp; // 指向函数的指针,函数地址
};
调用
一个类(Class)持有一系列的方法(Method),在load类时,runtime会将所
有方法的选择器(SEL)hash后映射到一个集合(NSSet)中(NSSet里的元素不
能重复)。
当需要发消息时,会根据选择器(SEL)去查找方法;找到之后,用Method结
构体里的函数指针(IMP)去调用方法。这样在运行时查找selecter的速度就会非
常快。
method_list_t * baseMethodList; //方法列表 里存的就是method_t
runtime方法直接调用
IMP imp = method_getImplementation(Method m);
// result保存方法的返回值,id表示调用这个方法的对象,SEL是Method的选择
器,argument是方法的参数。
id result = imp(id, SEL, argument);
SEL
// 获得SEL的三种方式
SEL selA = @selector(setTitle:);
SEL selB = sel_registerName("setTitle:");
SEL selC = NSSelectorFromString(@"setTitle:");
IMP
// 返回方法的具体实现
IMP class_getMethodImplementation(Class cls, SEL name);
IMP class_getMethodImplementation_stret(Class cls, SEL name);
// 类实例是否响应指定的selector
BOOL class_respondsToSelector(Class cls, SEL sel);
IMP
// 根据代码块获取IMP, 其实就是代码块与IMP关联
IMP imp_implementationWithBlock(id block)
// 根据Method获取IMP
IMP method_getImplementation(Method m)
// 根据SEL获取IMP
[[objc Class] instanceMethodForSelector:SEL]
Method
方法操作主要有以下函数:
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
// 添加方法
Method class_getInstanceMethod(Class cls, SEL name); // 获取实例方法
Method class_getClassMethod(Class cls, SEL name); // 获取类方法
Method *class_copyMethodList(Class cls, unsigned int *outCount); // 获
取所有方法的数组
// 替代方法的实现
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char
*types);
// 交换两个方法的实现
method_exchangeImplementations(Method m1, Method m2)