一、runtime简介
- Runtime 简称运行时。OC就是
运行时机制
,其中主要就是消息机制
。
- 对于C语言,函数在
编译期
就会决定调用哪个函数。
- 对于OC函数,属于
动态调用
,在编译期并不能真正决定调用哪个函数,只有在真正运行时候才会根据函数的名称找到对应的函数来调用。
- 事实证明
- 在编译阶段,OC可以
调用任何函数
,即使这个函数并未实现,只要声明过就不会报错。
- 在编译阶段,C语言调用
未实现的函数
就会报错。
二、runtime作用
1.发送消息
- 方法调用的本质,就是让对象发送消息。
- objc_msgSend,只有对象才能发送消息,因此以objc开头。
- 使用消息机制的前提,需导入
#import <objc/message.h>
1 2 3 4 5 6 7 8
| Person *p = [[Person alloc]init]; [p eat]; objc_msgSend(p,@selector(eat));
|
2.交换方法
场景:系统自带的方法功能不够,给系统自带方法扩展一些功能,并保持原有功能。
- 方法一:继承系统的类,重写方法。
- 方法二:使用runtime,交换方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @implementation UIImage (imageWithName) + (void)load{ Method imageWithName = class_getClassMethod(self, @selector(imageWithName:)); Method imageName = class_getClassMethod(self, @selector(imageNamed:)); method_exchangeImplementations(imageWithName, imageName); } + (instancetype)imageWithName:(NSString *)name{ UIImage *image = [self imageWithName:name]; if (image == nil) { NSLog(@"加载图片为空"); } return image; }
|
然后这里只需要在需要的地方调用+(UIImage)imageNamed:
方法就可以了,例如:
1 2 3 4 5 6 7
| @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIImage *image = [UIImage imageNamed:@"123"]; }
|
如果图片不存在的话,console就会输出加载图片为空
。
3.动态添加方法
1 2 3 4 5 6 7 8 9 10 11
| - (void)viewDidLoad { [super viewDidLoad]; Person *p = [[Person alloc]init]; [p performSelector:@selector(eat)]; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #import "Person.h" #import <objc/runtime.h> @implementation Person void eat(id self,SEL sel){ NSLog(@"%@ %@",self,NSStringFromSelector(sel)); } + (BOOL)resolveInstanceMethod:(SEL)sel{ if (sel == @selector(eat)) { * 动态添加方法 * * @param self cls:为哪个类添加方法 * @param sel SEL:添加方法的方法编号(方法名)是什么 * @param IMP IMP:方法实现 * @param const char * types方法类型 * * @return 返回是否添加成功 */ class_addMethod(self, sel, (IMP)eat, "v@:@"); } return [super resolveInstanceMethod:sel]; } @end
|
值得注意的是,最后一个参数@param const char *types
不太常用,通过官方文档查阅得知如下:
4.动态添加属性
category
中只能添加方法而不能直接添加属性,所以我们常常需要动态地来添加属性。
- 给一个类声明属性,其本质是给这个类添加关联,而不是直接把这个值得内存空间添加到类的内存空间中去。
1 2 3 4 5 6 7 8
| - (void)viewDidLoad { [super viewDidLoad]; NSObject *object = [[NSObject alloc]init]; object.name = @"壮壮"; NSLog(@"%@",object.name); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @implementation NSObject (property) - (NSString *)name{ return objc_getAssociatedObject(self, key); } - (void)setName:(NSString *)name{ 参数1:给哪个对象添加关联 参数2:关联的key,通过这个key来获取 参数3:管理的value 参数4:关联的策略 */ objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } @end
|