一.runtime简介
Runtime简称运行时,
OC
就是运行时机制
,也就是在运行的时候的一些机制,其中最主要的是消息机制.对于
C
语言,函数的调用在编译的时候会决定调用哪个函数.对于
oc
的函数,属于动态调用过程,在编译的时候并不能真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用.事实证明:
(1).在编译阶段,
oc
可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错.(2).在编译阶段,
c
语言调用未实现的函数就会报错
OC:运行时机制,消息机制是运行时机制最重要的机制
消息机制:任何方法调用,本质都是发送消息
二.runtime的使用
运行时,发送消息,谁做事请就拿谁
xcode5
之后,苹果不建议使用底层的方法
** xcode5
之后,使用运行时**(使用运行时的原因)
(1).方法调用的本质,就是让对象发送消息.objc_msgSend只有对象才能发消息,因此以objc开头,使用消息机制前提,必须导入#import
(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
@interface UIImage (Image)
+(__kindof UIImage *) jk_imageNamed:(NSString *)imageName;
@end
UIImage+Image.m
#import "UIImage+Image.h"
#import
@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
@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
@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