一.runtime简介
- Runtime简称运行时,
OC
就是运行时机制
,也就是在运行的时候的一些机制,其中最主要的是消息机制. - 对于
C
语言,函数的调用在编译的时候会决定调用哪个函数. - 对于
oc
的函数,属于动态调用过程,在编译的时候并不能真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用. - 事实证明:
- (1).在编译阶段,
oc
可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错. - (2).在编译阶段,
c
语言调用未实现的函数就会报错
OC:运行时机制,消息机制是运行时机制最重要的机制
消息机制:任何方法调用,本质都是发送消息
二.runtime的使用
运行时,发送消息,谁做事请就拿谁
xcode5
之后,苹果不建议使用底层的方法
** xcode5
之后,使用运行时**(使用运行时的原因)
(1).方法调用的本质,就是让对象发送消息.objc_msgSend只有对象才能发消息,因此以objc开头,使用消息机制前提,必须导入#import <objc/message.h>
(2).Build Setting -> 搜索msg -> 设置属性为NO
(3).真正的使用
在外面我定义了一个Person
的类,方法都进行了实现
消息机制调用对象方法:(调用的是多个参数的)
objc_msgSend(person, @selector(run:sdd:),25,@"名字");
额外提一句:类方法的调用:本质是把类名转化为类对象
//类方法的调用:本质是把类名转化为类对象 1.[Person eat]; 2.[[Person class]performSelector:@selector(eat)]; 3. id personClass = [Person class]; [personClass performSelector:@selector(eat)];
类方法运行机制的调用:
objc_msgSend([Person class], @selector(eat));
如果用一张图来表示的话就是下面的:
1.先用对象 -> 2.performSelector
-> 3.@selector
(方法:类似键)+有参数就添加 ->
4.这个对象的方法库里面寻找方法 -> 5.找到这个方法来调用
三.runtime交换方法
UIImage+Image.h
#import <UIKit/UIKit.h>
@interface UIImage (Image)
+(__kindof UIImage *) jk_imageNamed:(NSString *)imageName; @end
UIImage+Image.m
#import "UIImage+Image.h"
#import <objc/message.h>
@implementation UIImage (Image)
//交换的方法实现,方法都定义在类里面
/** * Class : 获取哪个类方法 * SEL : 获取方法编号,根据SEL就能去对应的类找方法 */ //获取类方法 //class_getClassMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>) //获取对象方法 //class_getInstanceMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>) +(void)load { //交换方法实现 //获取类方法 Method imageMethod = class_getClassMethod([UIImage class], @selector(imageNamed:)); Method jk_imageMethod = class_getClassMethod([UIImage class], @selector(jk_imageNamed:)); method_exchangeImplementations(imageMethod, jk_imageMethod); } +(UIImage *)jk_imageNamed:(NSString *)imageName { UIImage *image = [UIImage jk_imageNamed:imageName]; if (image == nil) { NSLog(@"图片为空"); }else { NSLog(@"图片不为空"); } return image; }
四.runtime动态添加方法(这里添加的是带参数的方法)
在此定义的是一个Son方法
// // Son.m // OC的runtime #import "Son.h" #import <objc/message.h> @implementation Son //定义函数 void eat(id self,SEL _cmd,id patam1) { /** * 系统默认会传方法 * */ NSLog(@"调用eat %@ %@ %@",self,NSStringFromSelector(_cmd),patam1); } //默认一个方法有两个参数,self,_cmd //self:方法的调用者 //_cmd:调用方法的编号 //动态添加方法,首先实现这个(没有实现的方法会走这里) +(BOOL) resolveInstanceMethod:(SEL)sel { //动态添加eat方法 /** * 对象方法的方法添加解释 * * @param cls#> 给那个类添加方法 * @param SEL#> 添加方法的方法编号 * @param imp#> 方法实现,函数入口,函数名 * @param types#> 方法类型 * */ // class_addMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>) if ([NSStringFromSelector(sel) isEqualToString:@"eat:"]) { // @:对象 : SEL class_addMethod(self, sel, (IMP)eat, "v@:@"); return YES; } return [super resolveInstanceMethod:sel]; } @end
五.runtime动态添加属性
给一个类动态的添加属性
我写了一个NSObject+shuxing.h类
NSObject+shuxing.h
生命一个属性
@property(nonatomic,strong) NSString *name;
NSObject+shuxing.m
#import "NSObject+shuxing.h" #import <objc/message.h> @implementation NSObject (shuxing) -(void)setName:(NSString *)name { //添加属性与对象有关 //给某个对象产生关联 /** * id object 给哪个对象添加属性 * const void *key 属性名,根据key去获取关联的对象 void * == id * id value 关联的值 * objc_AssociationPolicy policy 策略,用什么策略去保存 */ objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(NSString *)name { return objc_getAssociatedObject(self, @"name"); } @end
runtime部分代码 密码: kd5y