一、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
 |