iOS Runtime API 集锦

2020-02-17  本文已影响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];

上一篇下一篇

猜你喜欢

热点阅读