1.概念
runtime是OC底层的一套C语言的API,编译器最终都会将OC代码转化为运行时代码;
通过终端命令编译.m文件 clang -rewirte-objc xxx.m可以看到编译后的xxx.cpp(C++文件)。
调用方法本质就是发消息;
API:引入<objc/runtime.h>或<objc/message.h>
2.作用
动态交换两个方法的实现(特别是系统自带的方法);
动态添加对象的成员变量和成员方法;
获取某个类的所有成员方法、所有成员变量;
3.runtime的运用场景
将某些OC代码转为运行时代码,探究底层,比如block的实现原理;
拦截系统自带的方法调用(Swizzle 黑魔法),比如拦截imageNamed:、viewDidLoad、alloc;
实现分类(类目)也可以增加属性;
NSObject 添加分类 - 统计创建的对象个数
UIViewController 添加分类 - 统计创建控制器个数
原有控件或模块 添加功能
实现NSCoding的自动归档和自动解档;
实现字典和模型的自动转换。
4.runtime消息机制的调用流程
消息机制原理:对象根据方法编号SEL去映射表查找对应的方法实现;
5.案例
交换类方法
1 | //导入 头文件 |
拦截系统方法 imageNamed:
步骤:
1.创建类目(分类)
2.在 类目.h文件 添加自定义方法;
3.在 类目.m文件 导入<objc/runtime.h> 头文件,实现自定义方法和 在+(void)load{交换方法}
4.在 使用文件中导入类目头文件,使用系统方法即可
1 | //创建类目 |
给类目(分类)添加属性
步骤:
1.创建分类
2.在分类的.h文件添加属性
3.在.m文件导入<objc/runtime.h> 头文件,并且重写set、get的实现方法
set方法:将值value 跟对象object 关联起来(将值value 存储到对象object 中)
void objc_setAssociatedObject(id object , const void *key ,id value ,objc_AssociationPolicy policy)
get方法: 利用参数key 将对象object中存储的对应值取出来
id objc_getAssociatedObject(id object , const void *key)
参数说明:
object: 给哪个对象设置属性
key:一个属性对应一个key,通过key取出存储的值,key建议用char 节省字节(可以是double、int等)
value: 给属性设置的值
policy:存储策略(assign、copy、retain、strong) OBJC_ASSOCIATION_XXX
4.导入分类头文件使用属性即可
1 | /** |
获取一个类的所有成员变量
典型用法:归档和解档
获取某个类的所有成员变量
Ivar *class_copyIvarList(Class cls , unsigned int *outCount)
参数说明:
cls: 哪个类
outCount: 存放属性个数(一个接受值的地址)
获取成员变量名字
const char *ivar_getName(Ivar v)
获取成员变量的类型
const char *ivar_getTypeEndcoding(Ivar v)
1 | //导入头文件 |
获取所有属性重写归档解档方法
第三方库:MJExtension 中定义了归档解档的宏,一句宏搞定
步骤:
1.创建NSObject类目(分类)
2.在类目 .h文件定义方法
3.在类目 .m文件导入<objc/runtime.h> 头文件,并且写方法的实现方法
4.其他地方运用
1 | NSObject+XT.h |
获取所有属性来进行字典转模型
字典转模型三种情况:
当字典的key和模型的属性匹配不上;
模型中嵌套模型(模型属性是另外一个模型对象)
1.使用runtime 方法判断模型对象类型 ivar_getTypeEncoding()
2.对嵌套的模型对象 进行字典转模型(递归) - 注意排除系统的对象类型如NSString等
数组中装着模型(模型的属性是一个数组,数组中是一个个模型对象)
获取装有 模型的数组 的属性;
遍历数组中的每个模型并转为字典;
声明方法返回模型的类型;
方法一:KVC(局限性:模型属性和键值对 对应不上会crash,setValue:forUndefineKey:可防止crash)
方法二:runtime
1 |
|
参考资料:
1.OC中的RunTime运用
2.消息机制