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];
网友评论