• OC 反射-->动态创建类


    系统方法

     

     NSLog(@"%s", __func__);  //打印出类的方法名称,如:

    //打印结果:2018-02-22 10:52:15.394575+0800 DemoRuntime[1078:25503] -[ViewController printIvarList]

     

     

    创建Class


    1
    - (Class) createNewClass { 2 const char * className; 3 className = [@"Student" UTF8String]; 4 Class kclass = objc_getClass(className); 5 //判断此类是否已经存在,如果存在则返回,不存在就创建 6 if (!kclass) 7 { 8 Class superClass = [NSObject class]; 9 kclass = objc_allocateClassPair(superClass, className, 0); 10 } 11 return kclass; 12 }

     注册类

    1  Class newClass = [self createNewClass];
    2  id instanceObjects = [[newClass alloc] init];
    3  NSLog(@"注册后的类实例化对象:%@", instanceObjects);

    打印结果:


    添加成员变量

    1 //添加成员变量
    2 - (void) addNewVariable:(Class) newClass {
    3     class_addIvar(newClass, [@"_stuName" UTF8String], sizeof(NSString *), log2(sizeof(id)), "@");
    4 }
    1 //动态添加变量
    2 //入参:类Class,变量名char数组,变量类型大小size_t,变量在内存中的对齐方式,变量的type类型
    3 //返回:添加结果,是否成功。
    4 //* 1.只能给动态创建的类添加变量也就是用 objc_allocateClassPair 创建的类
    5 //* 2.添加变量只能在函数 objc_allocateClassPair 和 class_getInstanceVariable 之间添加才有效
    6 BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment, const char *types)

    注意:这个方法的调用要在objc_allocateClassPair方法之后和注册类objc_registerClassPair方法之前调用,否则没法动态添加成员变量。

    这是因为方法和属性并不“属于”类实例,而成员变量“属于”类实例。我们所说的“类实例”概念,指的是一块内存区域,包含了isa指针和所有的成员变量。所以假如允许动态修改类成员变量布局,已经创建出的类实例就不符合类定义了,变成了无效对象。但方法定义是在objc_class中管理的,不管如何增删类方法,都不影响类实例的内存布局,已经创建出的类实例仍然可正常使用。

    获取Class的成员变量名

     1 //    获取类的成员变量名
     2 - (NSArray *)getVariableNamesByObject:(id)object
     3 {
     4     unsigned int numIvars = 0;
     5 //    获取类的所有成员变量
     6     Ivar * ivars = class_copyIvarList([object class], &numIvars);
     7 //    定义一个数组来接收获取的属性名
     8     NSMutableArray *nameArray = [[NSMutableArray alloc] initWithCapacity:numIvars];
     9     for(int i = 0; i < numIvars; i++) {
    10 //        得到单个的成员变量
    11         Ivar thisIvar = ivars[i];
    12 //        得到这个成员变量的类型
    13         const char *type = ivar_getTypeEncoding(thisIvar);
    14         NSString *stringType =  [NSString stringWithCString:type encoding:NSUTF8StringEncoding];
    15 //        此处判断非object-c类型时跳过
    16         if (![stringType hasPrefix:@"@"]) {
    17             continue;
    18         }
    19 //        得到成员变量名
    20         NSString *variableName = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
    21         [nameArray addObject:variableName];
    22         
    23 //        这个函数可以得到成员变量的值
    24 //        object_getIvar(object, thisIvar)
    25         
    26     }
    27     free(ivars);
    28     return nameArray;
    29 }

    调用以后,结果为:


    创建方法

    第一个参数为类名,第二个参数为方法名,第三个参数是函数名,第四个参数是函数的返回值和参数的类型,v表是void,@表示id,:表示SEL。更多多定义参考:SELECTOR

    1    class_addMethod([kclass class], @selector(say:), (IMP)say, "v@:");
    1 //动态添加方法
    2 //入参:类Class,方法名SEL,方法实现IMP,方法返回值各个参数类型等配置字符串
    3 //返回:添加结果,是否成功。
    4 //* 1.添加属性不用再objc_registerClassPair之前,因为添加属性其实就是添加变量的set 和 get方法而已
    5 //* 2.添加的属性和变量不能用kvc设置值和取值
    6 BOOL class_addMethod(Class cls, SEL name, IMP imp,   const char *types)

    需要实现,这个方法


    添加属性

    1 //添加一个属性
    2 - (void) addProperties:(Class) newClass {
    3     NSString *propertyName = @"stuSex";
    4     objc_property_attribute_t type = { "T", "@"NSString"" };
    5     objc_property_attribute_t ownership = { "C", "copy" };
    6     objc_property_attribute_t backingivar  = { "V", [propertyName UTF8String]};
    7     objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    8     BOOL isOk=class_addProperty(newClass, [propertyName UTF8String], attrs, 3);
    9 }
    1 //动态添加属性
    2 //入参:类Class,属性名char数组,属性的配置属性,objc_property_attribute_t,属性的属性数量。
    3 //返回:添加结果,是否成功。
    4 BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)

     或者:

     1 + (void)addPropertyWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
     2     
     3     //先判断有没有这个属性,没有就添加,有就直接赋值
     4     Ivar ivar = class_getInstanceVariable([target class], [[NSString stringWithFormat:@"_%@", propertyName] UTF8String]);
     5     if (!ivar) {
     6         return;
     7     }
     8     //objc_property_attribute_t所代表的意思可以调用getPropertyNameList打印,大概就能猜出
     9     objc_property_attribute_t type = { "T", [[NSString stringWithFormat:@"@"%@"",NSStringFromClass([value class])] UTF8String] };
    10     objc_property_attribute_t ownership = { "&", "N" };
    11     objc_property_attribute_t backingivar  = { "V", [[NSString stringWithFormat:@"_%@", propertyName] UTF8String] };
    12     objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    13     if (class_addProperty([target class], [propertyName UTF8String], attrs, 3)) {
    14         
    15     //添加get和set方法
    16     SEL getter = NSSelectorFromString(propertyName);
    17     SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
    18         
    19     BOOL suc0 = class_addMethod([target class], getter, (IMP)attribute0Getter, "@@:");
    20     BOOL suc1 = class_addMethod([target class], setter, (IMP)attribute0Setter, "v@:@");
    21     NSLog(@">>>>>>>>添加get和set成功OrFail:%@:%@",@(suc0),@(suc1));
    22 
    23     NSLog(@">>>>>>>>1:%@",[target performSelector:getter withObject:nil]);
    24     [target performSelector:setter withObject:@"为动态创建类先添加变量再添加属性"];
    25     NSLog(@">>>>>>>>2:%@",[target performSelector:getter withObject:nil]);
    26         
    27     //赋值
    28     [target setValue:value forKey:propertyName];
    29     NSLog(@"%@", [target valueForKey:propertyName]);
    30     
    31     NSLog(@"创建属性Property成功");
    32     }
    33 }
    View Code
     1 //get方法
     2 NSString *attribute0Getter(id classInstance, SEL _cmd) {
     3     Ivar ivar = class_getInstanceVariable([classInstance class], "_attribute0");//获取变量,如果没获取到说明不存在
     4     return object_getIvar(classInstance, ivar);
     5 }
     6 
     7 //set方法
     8 void attribute0Setter(id classInstance, SEL _cmd, NSString *newName) {
     9     Ivar ivar = class_getInstanceVariable([classInstance class], "_attribute0");//获取变量,如果没获取到说明不存在
    10     id oldName = object_getIvar(classInstance, ivar);
    11     if (oldName != newName) object_setIvar(classInstance, ivar, [newName copy]);
    12 }
    get方法:第一个个@代表返回的类型为非基本数据类型,如果返回的数据是int那么第一个字符应该为i set方法:第一个个v代表返回的类型为void,如果返回的数据是int那么第一个字符应该为i,最后一个@代表函数的第一个试用参数类型为非基本数据类型 set和get方法的共同部分是@:分别代表方法的两个默认函数target和SEL。


    打印结果:

    查看属性

     1 //    获取类的所有属性名
     2 - (NSArray*)getPropertieNamesByObject:(id)object
     3 {
     4     
     5     unsigned int outCount, i;
     6     
     7 //    获取注册类的属性列表,第一个参数是类,第二个参数是接收类属性数目的变量
     8     objc_property_t *properties = class_copyPropertyList([object class], &outCount); 
     9 //    定义一个数组来接收获取的属性名
    10     NSMutableArray *nameArray = [[NSMutableArray alloc] initWithCapacity:outCount];
    11     for (i = 0; i < outCount; i++) {
    12 //        通过循环来获取单个属性
    13         objc_property_t property = properties[i];
    14 //        取得属性名
    15         NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
    16 //        将得到的属性名放入数组中
    17         [nameArray addObject:propertyName];
    18         
    19     }
    20     free(properties);
    21     return nameArray;
    22 }

    打印结果:


    查看方法

     1 -(void)getMethodsListByObject:(id) object {
     2     unsigned int copycopyMethodListCount = 0;
     3     Method *methods = class_copyMethodList([object class], &copycopyMethodListCount);
     4     for (NSInteger i = 0; i < copycopyMethodListCount; i++) {
     5         Method method = methods[i];
     6         SEL name = method_getName(method);
     7         NSLog(@">>>>>>>>2:copyMethodList:%@",NSStringFromSelector(name));
     8     }
     9     free(methods);//释放
    10     NSLog(@"
    ");
    11     
    12     }

    打印:


     添加协议

     1 //添加协议
     2 - (void)addProtocoalWithClass:(Class)class_1 {
     3     BOOL result0 = class_addProtocol(class_1, NSProtocolFromString(@"UITableViewDelegate"));
     4     NSLog(@">>>>>>>>3:添加协议成功");
     5 
     6     /**
     7      * 1.class_addProtocol  参数含义:第一个:要添加协议的类,第二个:协议对象
     8      * 2.获取协议列表具体细节参照Class1里的内容
     9      */
    10     unsigned int copyProtocolListCount = 0;
    11     Protocol * __unsafe_unretained *protocals = class_copyProtocolList(class_1, &copyProtocolListCount);
    12     for (NSInteger i = 0; i < copyProtocolListCount; i++) {
    13         Protocol * protocal = protocals[i];
    14         const char *name = protocol_getName(protocal);
    15         NSLog(@">>>>>>>>4:copyProtocolList:%s",name);
    16     }
    17     free(protocals);//释放
    18     NSLog(@"
    ");
    19 }

    打印结果:

  • 相关阅读:
    状压DP入门
    二分图匹配(最大匹配:匈牙利算法)
    序列自动机入门
    Trie树入门+例题(字典树,前缀树)
    扩展KMP算法(Z-Algorithm)
    Oracle锁表查询和解锁方法
    oracle获取系统日期--当前时间+前一天+当前月+前一个月
    oracle获取年月日,两个日期相减
    oracle decode函数和 sign函数
    expdp、impdp数据泵导出导入数据
  • 原文地址:https://www.cnblogs.com/EchoHG/p/8432752.html
Copyright © 2020-2023  润新知