不能向编译后得到的类中增加实例变量!
能向运行时创建的类中添加实例变量!
因为编译后的类已经注册在runtime中,类结构体中的objc_ivar_list
实例变量的链表和instance_size
实例变量的内存大小已经确定,同时runtime 会调用
class_setIvarLayout
或 class_setWeakIvarLayout
来处理strong weak引用,所以不能向存在的类中添加实例变量。
运行时创建的类是可以添加实例变量,调用 class_addIvar
函数,但是得在调用 objc_allocateClassPair
之后,objc_registerClassPair
之前,原因同上。
/** * Adds a new instance variable to a class. * * @return YES if the instance variable was added successfully, otherwise NO * (for example, the class already contains an instance variable with that name). * * @note This function may only be called after objc_allocateClassPair and before objc_registerClassPair. * Adding an instance variable to an existing class is not supported. * @note The class must not be a metaclass. Adding an instance variable to a metaclass is not supported. * @note The instance variable's minimum alignment in bytes is 1<<align. The minimum alignment of an instance * variable depends on the ivar's type and the machine architecture. * For variables of any pointer type, pass log2(sizeof(pointer_type)). */ OBJC_EXPORT BOOL class_addIvar(Class _Nullable cls, const char * _Nonnull name, size_t size, uint8_t alignment, const char * _Nullable types) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
已经编译好的类,调用 class_addIvar 函数,总是会返回 NO ,就是这个原因。
想返回 YES ,只能在运行时,重新创建一个新类,才可以。
//在运行时创建继承自NSObject的People类 Class People = objc_allocateClassPair([NSObject class], "People", 0); //添加_name成员变量 BOOL flag1 = class_addIvar(People, "_name", sizeof(NSString*), log2(sizeof(NSString*)), @encode(NSString*)); if (flag1) { NSLog(@"NSString*类型 _name变量添加成功"); } //添加_age成员变量 BOOL flag2 = class_addIvar(People, "_age", sizeof(int), sizeof(int), @encode(int)); if (flag2) { NSLog(@"int类型 _age变量添加成功"); } //完成People类的创建 objc_registerClassPair(People); unsigned int varCount; //拷贝People类中的成员变量列表 Ivar * varList = class_copyIvarList(People, &varCount); for (int i = 0; i<varCount; i++) { NSLog(@"%s",ivar_getName(varList[i])); } //释放varList free(varList); //创建People对象p1 id p1 = [[People alloc]init]; //从类中获取成员变量Ivar Ivar nameIvar = class_getInstanceVariable(People, "_name"); Ivar ageIvar = class_getInstanceVariable(People, "_age"); //为p1的成员变量赋值 object_setIvar(p1, nameIvar, @"张三"); object_setIvar(p1, ageIvar, @33); //获取p1成员变量的值 NSLog(@"%@",object_getIvar(p1, nameIvar)); NSLog(@"%@",object_getIvar(p1, ageIvar));
调用结果
2021-07-16 13:54:20.021525+0800 Test[6914:114952] NSString*类型 _name变量添加成功 2021-07-16 13:54:20.021655+0800 Test[6914:114952] int类型 _age变量添加成功 2021-07-16 13:54:20.021740+0800 Test[6914:114952] _name 2021-07-16 13:54:20.021810+0800 Test[6914:114952] _age 2021-07-16 13:54:20.021913+0800 Test[6914:114952] 张三 2021-07-16 13:54:20.022003+0800 Test[6914:114952] 33