前言
runtime的资料网上有很多了,部分有些晦涩难懂,我通过自己的学习方法总结一遍,主要讲一些常用的方法功能,以实用为主,我觉得用到印象才是最深刻的,并且最后两个demo也是MJExtension的实现原理,面试的时候也可以多扯点。
另外runtime的知识还有很多,想要了解更多可以看我翻译的官方文档(有点枯燥),本文的demo下载地址
什么是runtime?
runtime 是 OC底层的一套C语言的API(引入 或
),编译器最终都会将OC代码转化为运行时代码,通过终端命令编译.m 文件:
clang -rewrite-objc xxx.m
可以看到编译后的xxx.cpp(C++文件)。
比如我们创建了一个对象 [[NSObject alloc]init]
,最终被转换为几万行代码,截取最关键的一句可以看到底层是通过runtime创建的对象
删除掉一些强制转换语句,可以看到调用方法本质就是发消息,[[NSObject alloc]init]
语句发了两次消息,第一次发了alloc 消息,第二次发送init 消息。利用这个功能我们可以探究底层,比如block的实现原理。
需要注意的是,使用objc_msgSend()
sel_registerName()
方法需要导入头文件
另外利用runtime 可以做一些OC不容易实现的功能
- 动态交换两个方法的实现(特别是交换系统自带的方法)
- 动态添加对象的成员变量和成员方法
- 获得某个类的所有成员方法、所有成员变量
如何应用运行时?
1.将某些OC代码转为运行时代码,探究底层,比如block的实现原理(上边已讲到);
2.拦截系统自带的方法调用(Swizzle 黑魔法),比如拦截imageNamed:、viewDidLoad、alloc;
3.实现分类也可以增加属性;
4.实现NSCoding的自动归档和自动解档;
5.实现字典和模型的自动转换。
下面我通过demo 我一个个来讲解
一、交换两个方法的实现,拦截系统自带的方法调用功能
需要用到的方法
- 获得某个类的类方法
1 Method class_getClassMethod(Class cls , SEL name)- 获得某个类的实例对象方法
1 Method class_getInstanceMethod(Class cls , SEL name)- 交换两个方法的实现
1 void method_exchangeImplementations(Method m1 , Method m2)
案例1:方法简单的交换
创建一个Person类,类中实现以下两个类方法,并在.h 文件中声明
1 2 3 4 5 6 7 |
+ (void)run { NSLog(@"跑"); } + (void)study { NSLog(@"学习"); } |
控制器中调用,则先打印跑,后打印学习
1 2 |
[Person run]; [Person study]; |
下面通过runtime 实现方法交换,类方法用class_getClassMethod
,对象方法用class_getInstanceMethod
1 2 3 4 5 6 7 8 |
// 获取两个类的类方法 Method m1 = class_getClassMethod([Person class], @selector(run)); Method m2 = class_getClassMethod([Person class], @selector(study)); // 开始交换方法实现 method_exchangeImplementations(m1, m2); // 交换后,先打印学习,再打印跑! [Person run]; [Person study]; |
案例2:拦截系统方法
需求:比如iOS6 升级 iOS7 后需要版本适配,根据不同系统使用不同样式图片(拟物化和扁平化),如何通过不去手动一个个修改每个UIImage的imageNamed:方法就可以实现为该方法中加入版本判断语句?
步骤:
1、为UIImage建一个分类(UIImage+Category)
2、在分类中实现一个自定义方法,方法中写要在系统方法中加入的语句,比如版本判断
1 2 3 4 5 6 7 8 |
+ (UIImage *)xh_imageNamed:(NSString *)name { double version = [[UIDevice currentDevice].systemVersion doubleValue]; if (version >= 7.0) { // 如果系统版本是7.0以上,使用另外一套文件名结尾是‘_os7’的扁平化图片 name = [name stringByAppendingString:@"_os7"]; } return [UIImage xh_imageNamed:name]; } |
3、分类中重写UIImage的load方法,实现方法的交换(只要能让其执行一次方法交换语句,load再合适不过了)
1 2 3 4 5 6 7 |
+ 也可以多扯点。 另外runtime的知识还有很多,想要了解更多可以看我翻译的官方文档(有点枯燥),本文的demo下载地址 什么是runtime?runtime 是 OC底层的一套C语言的API(引入 .cpp 文件
删除掉一些强制转换语句,可以看到调用方法本质就是发消息, 消息机制
另外利用runtime 可以做一些OC不容易实现的功能
如何应用运行时?1.将某些OC代码转为运行时代码,探究底层,比如block的实现原理(上边已讲到); 下面我通过demo 我一个个来讲解一、交换两个方法的实现,拦截系统自带的方法调用功能
案例1:方法简单的交换创建一个Person类,类中实现以下两个类方法,并在.h 文件中声明
控制器中调用,则先打印跑,后打印学习
下面通过runtime 实现方法交换,类方法用
案例2:拦截系统方法
步骤:
3、分类中重写UIImage的load方法,实现方法的交换(只要能让其执行一次方法交换语句,load再合适不过了)
|