Runtime个别API的使用

Runtime 关于属性部分API的说明以及使用方法

 

使用Runtime机制需要引入头文件:

  #import <objc/runtime.h>

 

1:  Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

作用: 

复制一个类中的所有属性(私有属性, 公开属性),并返回一个列表

使用方法:

    unsigned int outCount; // 声明无符号整型变量

        Ivar *ivars = class_copyIvarList([self class], &outCount); // [self class] 您要查询的类,如果查询的是当前使用的类 那么[self class] , 如果是一个对象例如:UserModel *userModel = [UserModel new]; 如果我们查询对象userModel中的属性列表,可以是使用[userModel class];    &outCount 这里是获取 outCount的指针,并给变量 outCount 赋值, 返回值 ivars 这里得到的是 Ivar 类型的集合 

        if (outCount > 0) { 

            for (int i = 0; i < outCount; i ++) {

                Ivar ivar = ivars[i];

                NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)]; // 这里是获取我们定义的属性名称,并转化为字符串对象格式是实例变量的格式:_变量名 , 也就是:带下划线+属性名称例如userModel有一个字符串属性name,那么 key 的值为 _name

            }

        }

 

区别:  objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

  @interface ViewController : UIViewController

  {

      NSString *descriptionName;

  }

  @property(nonatomic , copy) NSString *names;

  @property (nonatomic , assign) float floatNum;

  @end

  objc_property_t *objc_property = class_copyPropertyList([self class], &outCount);

      NSLog(@"outCount is %u" , objc_property);

  打印结果: 2 

  说明: class_copyPropertyList 这个方法无法获取到实例变量 descriptionName,只能获取到成员变量(@property 声明的变量)

  Ivar *ivarsNew = class_copyIvarList([self class], &outCount);

  NSLog(@"outCount is %u" , ivarsNew);

  打印结果: 3  class_copyIvarList 这个方法可以获取到类中的所有变量不管成员变量还是实例变量

2:  const char *ivar_getName(Ivar v)

作用:

通过 Ivar 获取属性名称,返回类型 char 类型,通过 [NSString stringWithUTF8String:ivar_getName(ivar)]方法可以转化为字符串类型

使用方法: 

必须获取到属性的 Ivar 指针

方式1:

可以通过 class_copyIvarList(Class cls, unsigned int *outCount) 方法获取 Ivar 的列表集合

例如:

    unsigned int outCount; // 声明无符号整型变量

        Ivar *ivars = class_copyIvarList([self class], &outCount); // 假如 self 中的第一个属性名称为 name

    Ivar ivar = ivars[0]; // 获取属性列表中的首个

    NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];

        NSLog(propertyName);

    打印结果: _name

方式2:

可以通过 Ivar class_getInstanceVariable(Class cls, const char *name) 方法直接获取 Ivar

  UserModel *userModel = [UserModel new]; // 假如 userModel 中有一个 name 的属性,这里我们不用管属性的类型

  Ivar ivar = class_getInstanceVariable([userModel class], [@"_name" UTF8String]); // 假如 self 中有名称为name的属性

  if (ivar) { // 如果有名称为 name 的属性那么 ivar 不为空

    NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)];

           NSLog(propertyName);

      打印结果: _name

  }

3:  Ivar class_getInstanceVariable(Class cls, const char *name)

作用:

获取一个类中某个属性的 Ivar 

使用方法:

  UserModel *userModel = [UserModel new]; // 假如 userModel 中有一个 name 的属性,这里我们不用管属性的类型

  Ivar ivar = class_getInstanceVariable([userModel class], [@"_name" UTF8String]); // 属性1: 你要查询的类, 属性2: 实例变量(格式:_属性名)的字符类型

  if (ivar) {

    // 如果 userModel 类中有属性名称name的属性,可以在下面处理

  }

4:  const char *ivar_getTypeEncoding(Ivar v)

作用:

获取属性的类型

使用方法:

  UserModel *userModel = [UserModel new]; // 假如 userModel 中有一个 name  的属性,类型 NSString

  Ivar ivar = class_getInstanceVariable([userModel class], [@"_name" UTF8String]);

  if (ivar) {

    const char *s = ivar_getTypeEncoding(ivarName); // 获取类型的字符集

    NSString *key = [NSString stringWithUTF8String:s]; // 将类型的字符集转化为字符串

    NSLog(key);

    打印结果: NSString

    注释:

      不同的类型返回值得结果(注意大小写)为下面列表: 

      NSString: NSString

      BOOL: B

      NSInteger: q

      CGFloat: f

      float: f

      double: d

      int: i

  }

5:  id object_getIvar(id obj, Ivar ivar)

作用:

获取属性的返回值 

强调: 这里只能获取对象类型的属性值,例如属性类型为NSString类型,我们可以获取到他的 value 值, 如果为 int , BOOL , double , NSTimeInterval , CGFloat , float 我们不能通过这个方法获取属性的 value 值,如果使用这个方法会报错

使用方法:

     这里创建一个类,有下面一些属性

  @interface UserModel : NSObject

  @property (nonatomic , copy) NSString *name;

  @property (nonatomic , assign) NSInteger age;

  @property (nonatomic , assign) double height;

  @end

  .m文件不用管

  在使用 Runtime 机制的类中创建 UserModel 类

  UserModel *userModel = [UserModel new];

  userModel.name = @"李";

  userModel.age = 27;

  userModel.height = 180.1;

  Ivar ivarName = class_getInstanceVariable([userModel class], [@"_name" UTF8String]); // 获取查询对象的 Ivar 值

    id name = object_getIvar(userModel, ivarName); // 属性1: 要查询的对象 , 属性2: 我们要查询的对象中的属性(必须是:对象属性)的 Ivar 值

      if (name) { // 如果返回值不为空

        NSLog(name);

    打印结果:  李

      }

    // 那么下面使用获取 age 属性的值

  Ivar ivarAge = class_getInstanceVariable([userModel class], [@"_name" UTF8String]);

    id age = object_getIvar(userModel, ivarAge); // 这里会报错,并且你也无法获取到错误信息,所以如果获取非对象类型的属性值不能使用这个方法

  解决方法1:

    double myDoubleValue;

    object_getInstanceVariable(userModel, [@"_height" UTF8String], (void*)&myDoubleValue);

    NSLog(@"%f", myDoubleValue);  

    注释: 

      这里是通过运行时的 Ivar object_getInstanceVariable(id obj, const char *name, void **outValue) 方法获取对象属性的 value 值,我们先不管这个方法的能不能使用,首先一点就是,这个方法是C的方法,并且不支持ARC环境,我们现在开发基本上都是在ARC环境下开发,所以ARC的绕过,MRC就不写了,因为我已经不再使用MRC开发了

  解决方法2:

    通过 valueForKey: 方法获取返回值(这个方法不是运行时方法)

    Ivar ivarAge = class_getInstanceVariable([userModel class], [@"_name" UTF8String]); // 获取对象属性的 Ivar 值

    NSString *propertyAge = [NSString stringWithFormat:@"%s" , ivar_getName(ivarD)]; // 获取属性的实例变量名称例如: _age

    if (propertyAge) {

      NSString *valueForKeyPropertyAge = [userModel valueForKey:propertyAge]; //  valueForkey 返回值为 id 类型,我们可以统一使用字符串接收,或者使用相应的声明类型,比如int类型: int valueForKeyPropertyAge = [userModel valueForKey:propertyAge];

        } 

    我们也可以不通过运行时的方法获取

    NSString *value = [userModel valueForKey:@"_age"]; // 这里我们通过 key 值直接获取对象 userModel 对应属性的 value 值

posted @ 2017-03-23 20:01  li625317534  阅读(379)  评论(0编辑  收藏  举报