免费开源的iOS开发学习平台

Runtime简介:2-动态改变变量值和动态增加方法

Objective-C具有相当多的动态特性,常见的有动态类型(Dynamic typing),动态绑定(Dynamic binding)和动态加载(Dynamic loading),这些动态特性都是在Cocoa程序开发时较为常用的语言特性。另外,Objective-C的动态特性在运行时Runtime中也体现的淋漓尽致,例如可以动态去修改某个变量/属性的值,以及给某个类动态增加新的方法。

动态修改变量的值

我们继续使用上一篇中定义的Person类,在Person类中,添加一个类方法来为Person类对象赋初始值。

+(instancetype) person{
    Person *p = [[Person alloc] init];
    p.name = @"shixin";
    p.age = 35;
    p.height = 1.75;
    return p;
}

当我们创建一个Person类对象后,我们可以通过运行时Runtime来找到这个对象对应的所有属性/实例变量,然后对属性进行动态修改。例如,下面的代码中,我们对Person类的对象的name属性的值进行了修改。

/*动态修改属性值*/
-(void)changePropertyValue:(Person *)person {
    unsigned int count = 0;
    Ivar *ivar = class_copyIvarList([Person class], &count);
    for (int i = 0; i<count; i++) {
        Ivar var = ivar[i];
        const char *varName = ivar_getName(var);
        NSString *name = [NSString stringWithUTF8String:varName];
        if ([name isEqualToString:@"_name"]) {
            //动态修改_name实例变量的值
            object_setIvar(person, var, @"sx");
            break;
        }
    }
}

我们可以通过如下代码进行测试调用changePropertyValue:方法前后,person.name对象值。

    Person *person = [Person person];
    NSLog(@"1--%@--%d--%f", person.name,person.age,person.height);
    //动态修改属性的值
    [self changePropertyValue:person];
    NSLog(@"2--%@--%d--%f", person.name,person.age,person.height);

运行结果如下:

动态增加方法

在Runtime中提供了class_addMethod()函数来给某个类添加一个方法,如下所示,调用该函数需要提供4个参数,其主要含义是:

OBJC_EXPORT BOOL class_addMethod(Class cls, SEL name, IMP imp, 
                                 const char *types) ;
  • Class cls: 需要添加方法的类名称
  • SEL name:需要添加方法对应的选择器的名称(一般和方法同名)
  • IMP imp: 新增一个函数来定义新增方法的实现
  • const char *types: 新增方法的返回值和参数说明
/*动态添加方法*/
-(void) addMethod:(Person *)person  {
    //给person对象添加一个addMethod方法
     class_addMethod([person class], @selector(addMethod), (IMP)addMethod, "v@:");
    //如果Person中没有实现addMethod方法,则调用addMethod方法
    if ([person respondsToSelector:@selector(addMethod)]) {
        [person performSelector:@selector(addMethod)];
    }
}
//新增方法对应的函数实现
void addMethod (id self,SEL _cmd){
    NSLog(@"added method execute!");
}

当调用addMethod:方法时,运行结果如下。addMethod()中的代码会被执行。