iOS 开发中runtime虽然不是经常用到,但是runtime真的很有用,掌握一点runtime的只是,对于开发是非常有好处的,下面说一下我对runtime的理解。
1.首先runtime对象绑定,可以把一个变量绑定在另一个变量上,当绑定变量的事件结束是不会被释放,等到被绑定变量释放的时候,才会一起释放。
@implementation ViewController
//定义一个全局的静态变量
static NSString *str;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string=@"run time pass";
/*
*绑定需要四个参数 分别是 被绑定的对象 唯一的key(一般用静态变量的地址) 需要绑定的对象 一种关联策略(和设置属性时相同)
*/
objc_setAssociatedObject(self, &str, string, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
UIButton *button=[[UIButton alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
button.backgroundColor=[UIColor redColor];
[button addTarget:self action:@selector(runTimePass) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
-(void)runTimePass{
/*
*获取绑定的对象 两个参数 被绑定的对象 和唯一的key
*/
NSString *string=(NSString *)objc_getAssociatedObject(self, &str);
NSLog(@"%@",string);
}
下面是运行结果
2.方法互换 具体看代码
dispatch_once(&onceToken, ^{
//第一个参数是 Class的对象 第二个参数是SEL
Method runTimePass = class_getInstanceMethod([self class], @selector(runTimePass:));
Method runTimePassExchange = class_getInstanceMethod([self class], @selector(runTimePassExchange:));
method_exchangeImplementations(runTimePass, runTimePassExchange);
//这里最好加点运行时的代码,在willTransitionToState出来之前运行替换的函数,切记一定要替换一次 如果多次替换 会造成混乱
});
下面是结果图
3.在category里面添加方法
#import "UITableViewRowAction+Extension.h"
#import <objc/runtime.h>
@implementation UITableViewRowAction (Extension)
/*
*这里面实现各个属性的setter getter 方法
*/
- (void)setImage:(UIImage *)image {
objc_setAssociatedObject(self, @selector(image), image, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setEnabled:(BOOL)enabled {
objc_setAssociatedObject(self, @selector(enabled), @(enabled), OBJC_ASSOCIATION_ASSIGN);
}
- (void)setFont:(NSInteger)font {
objc_setAssociatedObject(self, @selector(font), @(font), OBJC_ASSOCIATION_ASSIGN);
}
- (UIImage *)image {
return objc_getAssociatedObject(self, _cmd);
}
- (NSInteger)font {
NSNumber *number=objc_getAssociatedObject(self, _cmd);
return number.integerValue;
}
- (BOOL)enabled {
id enabled = objc_getAssociatedObject(self, _cmd);
return enabled ? [enabled boolValue] : true;
}
@end
4.异常拦截 就是调用一个类中的方法,但是方法没用实现,在消息传递机制中,可以在抛异常之间进行处理(1)调用基类的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
//写一个C语言的函数 _cmd表示本类的方法
void dynamicMethodIMP(id self, SEL _cmd)
{
NSLog(@"SEL %s did not exist\n",sel_getName(_cmd));
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(runTimePass))
{ /*
*四个参数 Class对象 SEL添加的方法 方法的实现 方法的签名
*/
class_addMethod([self class], sel, (IMP) dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
下面是运行结果
2016-07-22 21:50:55.301 runTimeDemo[10830:442982] SEL runTimePass did not exist
2016-07-22 21:50:55.449 runTimeDemo[10830:442982] SEL runTimePass did not exist
2016-07-22 21:50:55.580 runTimeDemo[10830:442982] SEL runTimePass did not exist
2016-07-22 21:50:55.720 runTimeDemo[10830:442982] SEL runTimePass did not exist
- (id)forwardingTargetForSelector:(SEL)aSelector{
return [MyExchangeController new];
}
(3)将信息获取打包,然后处理信息
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *sig = nil;
NSString *selStr = NSStringFromSelector(aSelector);
if ([selStr isEqualToString:@"saveAction"]) {
//此处返回的sig是方法forwardInvocation的参数anInvocation中的methodSignature
sig = [self.con methodSignatureForSelector:@selector(runTimePass)];
}else{
sig = [super methodSignatureForSelector:aSelector];
}
return sig;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSString *selStr = NSStringFromSelector(anInvocation.selector);
if ([selStr isEqualToString:@"saveAction"]) {
[anInvocation setTarget:self.con];
[anInvocation setSelector:@selector(runTimePass)];
BOOL hasCompanyName = YES;
//第一个和第一个参数是target和sel
[anInvocation setArgument:&hasCompanyName atIndex:2];
[anInvocation retainArguments];
[anInvocation invoke];
}else{
[super forwardInvocation:anInvocation];
}
}
以上就是我对runtime的个人理解,其实runtime的用处不仅仅是这些,以后还会带来深入解析,欢迎大家多多与我交流。