动态添加成员变量和属性

273 阅读1分钟

类的 class_rw_t 结构体的 flags 信息

#define RW_REALIZED           (1<<31)// class_t->data 的结构为 class_rw_t,非class_ro_t
#define RW_METHODIZED         (1<<30)// 类的方法列表已修复
#define RW_INITIALIZED        (1<<29)// 类已经初始化了
#define RW_INITIALIZING       (1<<28)// 类在初始化过程中
#define RW_COPIED_RO          (1<<27)// class_rw_t->ro 是 class_ro_t 的堆副本
#define RW_CONSTRUCTING       (1<<26)// 类分配了内存,但没有注册
#define RW_CONSTRUCTED        (1<<25)// 类分配了内存也注册了
#define RW_FINALIZE_ON_MAIN_THREAD (1<<24)// GC:class有不安全的finalize方法
#define RW_LOADED             (1<<23)// 类的 +load 被调用了
#define RW_REALIZING          (1<<19)// 类已开始分配,但并未完成

一、动态添加类

 //初始化
 objc_allocateClassPair(_:_:_:)->objc_initializeClassPair_internal(_:_:_:_:)
 //设置flags标记信息
 //类分配了内存,但没有注册|class_rw_t->ro 是 class_ro_t 
     | class_t->data 的结构为 class_rw_t | 类已开始分配,但并未完成
 cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
 meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
 
 //注册到内存
 objc_registerClassPair(_:)
 cls->ISA()->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
 cls->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);

二、添加成员变量

 This function may only be called after objc_allocateClassPair(_:_:_:) and before objc_registerClassPair(_:). Adding an instance variable to an existing class is not supported.
 这个功能只能在 objc_allocateClassPair(_:_:_:) 之后和 objc_registerClassPair(_:) 之前调用。不支持将实例变量添加到现有的类。

 The class must not be a metaclass. Adding an instance variable to a metaclass is not supported.
 该类不能是元类。不支持将实例变量添加到元类。

 class_addIvar()
    // Can only add ivars to in-construction classes.
    if (!(cls->data()->flags & RW_CONSTRUCTING)) {
        return NO;
    }   
    

三、添加成员变量addIvar

Class Person = objc_allocateClassPair([NSObject class], "Person", 0);
objc_registerClassPair(Person);
class_addIvar(Person, "name", sizeof(NSString *), 0, "@");

无法添加成功
1、类注册到内存中后,ro无法修改。
2、在类注册到内存后,底层源码把类的flags值修改了,再调用class_addIvar()时,判断flags直接returnNO了。

四、添加属性

   class_addProperty(_:_:_:_:);//Person添加name属性
   [Person setValue:@"nn" forKey:@"name"];
   
  调用会闪退
  因为setValue: forKey:的本质是调用setName方法,直接调用会无法找到方法,必须先动态添加setget方法