zoukankan      html  css  js  c++  java
  • Runtime的用法有哪几种

    1, 动态添加一个类, 就像KVO一样, 系统是在程序运行的时候根据你要监听的类, 动态添加一个新类继承自该类, 然后重写原类的setter方法并在里面通知observer的.

    // 创建一个类(size_t extraBytes该参数通常指定为0, 该参数是分配给类和元类对象尾部的索引ivars的字节数。)
    Class clazz = objc_allocateClassPair([NSObject class], "GoodPerson", 0);
    
    // 添加ivar
    // @encode(aType) : 返回该类型的C字符串
    class_addIvar(clazz, "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
    
    class_addIvar(clazz, "_age", sizeof(NSUInteger), log2(sizeof(NSUInteger)), @encode(NSUInteger));
    
    // 注册该类
    objc_registerClassPair(clazz);
    
    // 创建实例对象
    id object = [[clazz alloc] init];
    
    // 设置ivar
    [object setValue:@"Tracy" forKey:@"name"];
    
    Ivar ageIvar = class_getInstanceVariable(clazz, "_age");
    object_setIvar(object, ageIvar, @18);
    
    // 打印对象的类和内存地址
    NSLog(@"%@", object);
    
    // 打印对象的属性值
    NSLog(@"name = %@, age = %@", [object valueForKey:@"name"], object_getIvar(object, ageIvar));
    
    // 当类或者它的子类的实例还存在,则不能调用objc_disposeClassPair方法
    object = nil;
    
    // 销毁类
    objc_disposeClassPair(clazz);
    --------------------- 

    2,

    通过runtime获取一个类的所有属性

    Person *p = [[Person alloc] init];
    [p setValue:@"Kobe" forKey:@"name"];
    [p setValue:@18 forKey:@"age"];
    //    p.address = @"广州大学城";
    p.weight = 110.0f;
    
    // 1.打印所有ivars
    unsigned int ivarCount = 0;
    // 用一个字典装ivarName和value
    NSMutableDictionary *ivarDict = [NSMutableDictionary dictionary];
    Ivar *ivarList = class_copyIvarList([p class], &ivarCount);
    for(int i = 0; i < ivarCount; i++){
        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivarList[i])];
        id value = [p valueForKey:ivarName];
    
        if (value) {
            ivarDict[ivarName] = value;
        } else {
            ivarDict[ivarName] = @"值为nil";
        }
    }
    // 打印ivar
    for (NSString *ivarName in ivarDict.allKeys) {
        NSLog(@"ivarName:%@, ivarValue:%@",ivarName, ivarDict[ivarName]);
    }
    
    // 2.打印所有properties
    unsigned int propertyCount = 0;
    // 用一个字典装propertyName和value
    NSMutableDictionary *propertyDict = [NSMutableDictionary dictionary];
    objc_property_t *propertyList = class_copyPropertyList([p class], &propertyCount);
    for(int j = 0; j < propertyCount; j++){
        NSString *propertyName = [NSString stringWithUTF8String:property_getName(propertyList[j])];
        id value = [p valueForKey:propertyName];
    
        if (value) {
            propertyDict[propertyName] = value;
        } else {
            propertyDict[propertyName] = @"值为nil";
        }
    }
    // 打印property
    for (NSString *propertyName in propertyDict.allKeys) {
        NSLog(@"propertyName:%@, propertyValue:%@",propertyName, propertyDict[propertyName]);
    }
    
    // 3.打印所有methods
    unsigned int methodCount = 0;
    // 用一个字典装methodName和arguments
    NSMutableDictionary *methodDict = [NSMutableDictionary dictionary];
    Method *methodList = class_copyMethodList([p class], &methodCount);
    for(int k = 0; k < methodCount; k++){
        SEL methodSel = method_getName(methodList[k]);
        NSString *methodName = [NSString stringWithUTF8String:sel_getName(methodSel)];
    
        unsigned int argumentNums = method_getNumberOfArguments(methodList[k]);
    
        methodDict[methodName] = @(argumentNums - 2); // -2的原因是每个方法内部都有self 和 selector 两个参数
    }
    // 打印method
    for (NSString *methodName in methodDict.allKeys) {
        NSLog(@"methodName:%@, argumentsCount:%@", methodName, methodDict[methodName]);
    }
    ---------------------

    3, 

    动态变量控制,动态修改变量的值

    -(void)changeAge{
         unsigned int count = 0;
         //动态获取XiaoMing类中的所有属性[当然包括私有] 
         Ivar *ivar = class_copyIvarList([self.xiaoMing class], &count);
         //遍历属性找到对应age字段 
         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:@"_age"]) {
                 //修改对应的字段值成20
                 object_setIvar(self.xiaoMing, var, @"20");
                 break;
             }
         }
         NSLog(@"XiaoMing's age is %@",self.xiaoMing.age);
     }
    

    4, 

    在NSObject的分类中增加方法来避免使用KVC赋值的时候出现崩溃

    在有些时候我们需要通过KVC去修改某个类的私有变量,但是又不知道该属性是否存在,如果类中不存在该属性,那么通过KVC赋值就会crash,这时也可以通过运行时进行判断。同样我们在NSObject的分类中增加如下方法。

    #import "NSObject+objc.h"
    #import <objc/runtime.h>
    
    @implementation NSObject (objc)
    
    -(BOOL)hasProperty:(NSString *)property
    {
        BOOL flag = NO;
        u_int count = 0;
        Ivar *ivars = class_copyIvarList([self class], &count);
        for (int i = 0; i < count; i++) {
            const char *propertyName = ivar_getName(ivars[i]);
            NSString *propertyString = [NSString stringWithUTF8String:propertyName];
            if ([propertyString isEqualToString:property]){
                flag = YES;
            }
        }
        return flag;
    }
    
    @end

    5, 

    利用runtime的动态交换方法实现

    +(void)run
    {
        NSLog(@"Person Run.....");
    }
    
    +(void)study
    {
        NSLog(@"Person study.....");
    }
    // 获取两个类的类方法
        Method m1 = class_getClassMethod([Person class], @selector(run));
        Method m2 = class_getClassMethod([Person class], @selector(study));
        // 开始交换方法实现
        method_exchangeImplementations(m1, m2);
       [Person run];
        [Person study];

    6,

    动态添加方法

    // void(*)()
    // 默认方法都有两个隐式参数,
    void eat(id self,SEL sel)
    {
        NSLog(@"%@ %@",self,NSStringFromSelector(sel));
    }
    
    // 当一个对象调用未实现的方法,会调用这个方法处理,并且会把对应的方法列表传过来.
    // 刚好可以用来判断,未实现的方法是不是我们想要动态添加的方法
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
    
        if (sel == @selector(eat)) {
            // 动态添加eat方法
    
            // 第一个参数:给哪个类添加方法
            // 第二个参数:添加方法的方法编号
            // 第三个参数:添加方法的函数实现(函数地址)
            // 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd
            class_addMethod(self, @selector(eat), eat, "v@:");
    
        }
    
        return [super resolveInstanceMethod:sel];
    }
  • 相关阅读:
    IE8、IE9解决浏览器跨域。
    英语写作-Introduction
    qt添加图标
    Qt 编译错误 :cannot find file .pro
    python
    数据集
    基金
    visio2010求交操作
    书籍网站
    ROS安装xtion
  • 原文地址:https://www.cnblogs.com/dashengios/p/10596742.html
Copyright © 2011-2022 走看看