美文网首页
iOS Runtime API 集锦

iOS Runtime API 集锦

作者: 孙掌门 | 来源:发表于2020-02-17 21:29 被阅读0次

    iOS Runtime API 集锦

    runtime 作用其实很多:

    
    1. 利用关联对象给分类添加属性
    2. 遍历一个类所有的成员变量(json 解析)
    3. 交换方法(比如交换系统的某个方法)
    
    

    1 object_getClass

    object_getClass是获取 isa 指向的对象,实例对象的 isa 指向当前的类对象,类对象的isa指向的是元类对象

     NSLog(@"%p----%p---%p",object_getClass(test),object_getClass([Test class]),[Test class]);
    
    
    

    上面的打印结果为

    Test *test = [[Test alloc] init];
    
    0x10bca29a0----0x10bca2978---0x10bca29a0
    
    

    可以验证上面的话,第一三的打印相同,为什么呢?因为 test 是通过实例化生成的对象,他的isa指针应该指向当前的类对象,也就是 [Test class],当前的类对象应该指向元类对象,也就是第二个的打印结果,明白了吗?

    2 object_setClass

    object_setClass 这个 API 是改变当前对象 isa 指针所指向,

     Test *test = [[Test alloc] init];
        
        NSLog(@"%p----%p---%p",object_getClass(test),object_getClass([Test class]),[Test class]);
        [test print];
        object_setClass(test, [Runtime class]);
        [test print];
        
    

    结果

    2020-02-17 20:40:12.654033+0800 blogTest[51002:8159656] i am test
    2020-02-17 20:40:12.654166+0800 blogTest[51002:8159656] i am runtime
    
    

    可以看到,之后的打印,变成了打印 runtime,是不是很神奇?

    3 object_isClass

    object_isClass 判断是否为类对象

    Test *test = [[Test alloc] init];
    
    NSLog(@"%d----%d",object_isClass(test),object_isClass([Test class]));
    
    

    答案为01,这个很容易理解,我就不解释了。

    4. objc_allocateClassPair objc_registerClassPair

    动态添加一个类,动态添加属性和方法申请完之后要注册。

    void print(id self , SEL _cmd){
        NSLog(@"%@----%@",self,NSStringFromSelector(_cmd));
    }
    
    // 动态创建一个类  1.父类 2.类名 3.额外的大小
        Class person = objc_allocateClassPair([NSObject class], "SCXPerson", 0);
        // 添加年龄属性
        class_addIvar(person, "_age", 4, 1, @encode(int));
        // 动态添加方法
        class_addMethod(person, @selector(print), (IMP)print, "v@:");
        // 注册一个类
        objc_registerClassPair(person);
        object_setClass(test, person);
        [test print];
    
    

    上面的代码,显示动态申请了一个类,然后往这个类里面动态添加了属性和方法,最后注册了这个类,并把前面写到 的类的isa指向了这个新注册的类,我们看打印结果

    
     <SCXPerson: 0x600001e78d20>----print
    
    

    看懂了吗?是不是很好玩,很有意思。但是要记住,动态添加属性一定要写在注册之前,因为我们的属性是放在class_ro_t这个结构体,是制只读的,所以,要是类被注册完了之后,就不能修改了,所以 class_addIvar 这个方法也不能用在已经存在的类上面,而方法可以,方法是放在rw_t中。

    5. class_getInstanceVariable

    获取成员变量信息

    
    Ivar ivar = class_getInstanceVariable([Test class], "_a");
        NSLog(@"%s----%s",ivar_getName(ivar),ivar_getTypeEncoding(ivar));
    
    

    打印

    _a----i
    
    

    6. class_copyIvarList

    获取所有的成员变量

     //获取所有成员变量
        unsigned count = 0;
        Ivar *list = class_copyIvarList([Test class], &count);
        for (int i = 0 ; i < count; i ++) {
            Ivar var = list[i];
            NSLog(@"%s----%s",ivar_getName(var),ivar_getTypeEncoding(var));
        }
        free(list);
    
    

    7. class_replaceMethod

    class_replaceMethod替换方法

    
    Test *tt = [[Test alloc] init];
        class_replaceMethod([Test class], @selector(print), (IMP)run, "v@:");
        [tt print];
    
    

    8. method_exchangeImplementations

    method_exchangeImplementations交换方法实现

    
     Test *tt = [[Test alloc] init];
        
    //    class_replaceMethod([Test class], @selector(print), (IMP)run, "v@:");
    //    [tt print];
        
        Method run = class_getInstanceMethod([Test class], @selector(run));
        Method p = class_getInstanceMethod([Test class], @selector(print));
        method_exchangeImplementations(run, p);
        [tt print];
    
    

    相关文章

      网友评论

          本文标题:iOS Runtime API 集锦

          本文链接:https://www.haomeiwen.com/subject/qhgifhtx.html