runtime的概述
runtime的相关概念
runtime消息机制
消息传递
动态方法解析
消息转发
runtime的作用
runtime的应用
runtime的概述
oc作为一门动态语言,对象的真正类型以及真正要调用的方法是在运行时才确定的,这就决定了oc需要一套运行时的库来提供支持。runtim就是oc中运行时的库,是一套c语言的API。我们所写的oc代码在运行时都转成了runtime相关的代码,类转换成c语言对应的结构体,方法转化为c语言对应的函数,发消息转成了c语言对应的函数调用。其中最重要的就是消息机制。
消息机制:任何函数的调用本质都是发送消息。
和C的不同
对于C语言,函数的调用在编译的时候会决定调用哪个函数,如果调用未实现的函数就会报错。
对于OC语言,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错。
使用准备
用runtime需要导入头文件#import <objc/runtime.h>
使用运行时,发送消息(objc_msgSend)需要导入框架<objc/message.h>并且xcode5之后,苹果不建议使用底层方法,如果想要使用运行时,需要关闭严格检查objc_msgSend的调用,BuildSetting->搜索msg 改为NO。
消息机制原理
1,只有对象才能发送消息(类其实是类对象)
2,[p eat] 调用[p performSelector:@selector(eat)]调用objc_msgSend(p, @selector(eat));发消息底层是调用的C的运行时接口方法objc_msgSend
3,每个类创建时就会有自己的方法列表,SEL是根据类的方法名得到的一个整数编号
@selector方法选择器根据方法名找到对应的方法编号去方法列表找对应的函数地址,再根据地址去调用函数
实例方法调用底层实现
Person *p = [[Person alloc] init];
[p eat];
// 底层会转化成
//SEL:方法编号,根据方法编号就可以找到对应方法的实现。
[p performSelector:@selector(eat)];
//performSelector本质即为运行时,发送消息,谁做事情就调用谁 ,实际上是调用
objc_msgSend(p, @selector(eat));
// 带参数
objc_msgSend(p, @selector(eat:),10);
类方法的调用底层
// 本质是会将类名转化成类对象,初始化方法其实是在创建类对象。
[Person eat];
// Person只是表示一个类名,并不是一个真实的对象。只要是方法必须要对象去调用。
// RunTime 调用类方法同样,类方法也是类对象去调用,所以需要获取类对象,然后使用类对象去调用方法。
Class personclass = [Persion class];
[[Persion class] performSelector:@selector(eat)];
// 类对象发送消息
objc_msgSend(personclass, @selector(eat));
为一个类添加额外的功能可以使用子类,分类,运行时。
运行时交换方法
当系统自带的方法功能不够,需要给系统自带的方法扩展一些功能,并且保持原有的功能时,可以使用RunTime交换方法实现。
交换方法以后是调用时交换,实现还是以前的。
交换方法的不足:如果系统或者三方类的方法名没有暴露出来的话,不可以使用交换方法。
这是一个最简单的交换方法,将people中的run方法和控制器的m1方法交换,调用m2,实际是调用people的run的实现。
//people的.h文件
-(void)run;
//people的.m文件
- (void)run{
NSLog(@"人在跑");
}
//控制器
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self m2];
}
-(void)m2{
NSLog(@"狗在跑");
}
- (void)viewDidLoad {
[super viewDidLoad];
// m1存在的类
Method m1 = class_getInstanceMethod([People class], @selector(run));
// m2存在的类
Method m2 = class_getInstanceMethod([ViewController class], @selector(m2));
// 交换m1,m2的SEL
method_exchangeImplementations(m1, m2);
// Do any additional setup after loading the view, typically from a nib.
}
网友评论