iOS runtime 初探

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


(2)转给一个带有方法的类的对象

- (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;

        //第一个和第一个参数是targetsel

        [anInvocation setArgument:&hasCompanyName atIndex:2];

        [anInvocation retainArguments];

        [anInvocation invoke];

    }else{

        [super forwardInvocation:anInvocation];

    }

}

以上就是我对runtime的个人理解,其实runtime的用处不仅仅是这些,以后还会带来深入解析,欢迎大家多多与我交流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值