Runtime介绍
运行时,OC就是运行时机制,最主要的是消息机制。
对于C语言,函数的调用在编译的过程中会决定调用哪个函数。
对于OC,则属于动态调用过程,只有在真正运行的时候才会根据函数名找到对应的函数。
Runtime作用
1.发送消息
objc_msgSend
方法调用的本质,就是让对象发送消息。
2.交换方法method_exchangeImplementations
系统自带的方法功能不够时,想给系统自带的方法扩展一些功能,并且保持原有的功能。
3.动态添加方法class_addMethod
如果一个类的方法很多,加载类到内存的时候耗费资源,需要给每个方法生成映射表,可以使用动态给某个类,添加方法解决。
4.动态添加属性objc_setAssociatedObject
给一个类声明属性,其实本质就是给这个类添加关联,并不是直接把这个值的内存空间添加到类存空间,就是对象本身的属性可以关联到另外一个内存中。
发送消息
使用运行时的第一步:
1.#import <objc/message.h>
2.xcode-->build settings->搜索msg
我们先创建一个Person对象,创建一个类方法,一个对象方法,如下代码所示:
#import "Person.h"
@implementation Person
+ (void)eat
{
NSLog(@"类方法——吃饭");
}
- (void)eat
{
NSLog(@"对象方法——吃面");
}
@end
我们在控制器中调用,首先,#import "Person.h"
Person * p = [[Person alloc] init];
//我们一般调用对象方法,都会这样写:[p eat],
//现在用runtime让对象p发送一个消息。
objc_msgSend(p, @selector(eat));
//按照以前,我们调用类方法,都会是这样写的
//[Person eat] 那使用runtime调用类方法,跟调用对象方法类似。
//获取类对象
Class personClass = [Person class];
//运行时:拿到类对象,调用类方法。
objc_msgSend(personClass, @selector(eat));
ok,我们运行程序:
2017-01-18 10:46:22.940 [70808:6452367] 对象方法——吃面
2017-01-18 10:46:22.940 [70808:6452367] 类方法——吃饭
现在我再写一个对象方法,添加一个值,在控制器中传过去。
- (void)ride:(int)age
{
NSLog(@"%d",age);
}
控制器中调用
objc_msgSend(p, @selector(ride:),10);
运行结果:
2017-01-18 10:51:41.083 [71101:6456914] 10
如果我们不用runtime来发送消息,还有另外一种方式也可以调用类方法和对象方法,那就是SEL。
Person * p = [[Person alloc] init];
//SEL:方法编号,根据方法编号就可以找到对应方法实现,属于动态调用
[p performSelector:@selector(eat)];
//获取类对象
//类名调用类方法,本质类名转换成类对象
Class personClass = [Person class];
[personClass performSelector:@selector(eat)];
运行结果一样:
2017-01-18 10:46:22.940 [70808:6452367] 对象方法——吃面
2017-01-18 10:46:22.940 [70808:6452367] 类方法——吃饭