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)