ios runtime最常见的应用

1.动态绑定属性动态扩展属性

动态属性绑定说起来相当抽象,简单来说就是用到某一个对象的那个时刻给这个对象绑定额外的属性
先来一段代码

#import "UIViewController+Tools.h"
#import <objc/runtime.h>
static char * const TAG = "tag";

@implementation UIViewController (Tools)
-(void)setTagUIT:(NSString *)tag{
    objc_setAssociatedObject(self, TAG, tag,  OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)getTagUIT{
    NSString *tag =  objc_getAssociatedObject(self, TAG);
    return tag;
}
@end

这是对UIViewController的一个扩展,使得UIViewController多了一个设置属性和获取属性的方法


#import "ViewController.h"
#import "UIViewController+Tools.h"

@interface ViewController ()
@end
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton *button = [[UIButton alloc] init];
    button.frame = CGRectMake(50, 50, 100, 100);
    button.backgroundColor = [UIColor redColor];
    [button addTarget:self action:@selector(button1) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];

    button = [[UIButton alloc] init];
    button.frame = CGRectMake(50+150, 50, 100, 100);
    button.backgroundColor = [UIColor greenColor];
    [button addTarget:self action:@selector(button2) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}
-(void)button1{
    [self setTagUIT:@"TAG  UIT"];
    NSLog(@"button1");
}
-(void)button2{
    NSString *uit = [self getTagUIT];
    NSLog(@"button2  %@",uit);

}

或者这个案例没有什么感觉,但是现实开发中我们经常会碰到一个问题,就比如说点击列表然后提示(ios9之前)拨打电话,那么有时候需要将电话号码带入到Alert代理方法中

#import "ViewController.h"
#import <objc/runtime.h>


static char * const ALET = "alert";

@interface ViewController ()<UIAlertViewDelegate>
@end
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *button = [[UIButton alloc] init];
    button.frame = CGRectMake(50, 50, 100, 100);
    button.backgroundColor = [UIColor redColor];
    [button addTarget:self action:@selector(button1) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}
-(void)button1{
     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"OK"];
    [alertView show];
    objc_setAssociatedObject(alertView, ALET, @"15911111111", OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    NSString *phone = objc_getAssociatedObject(alertView, ALET);
    NSLog(@"%d",buttonIndex);
}

其实上面的代码就是对UIAlertView动态属性绑定,所以ios9之后Apple果断的方便开发者将UIAlertView 和 UIActionSheet API做了修改

2.UIButton点击事件改用block

将UIButton的点击事件换成block的写法,block不仅仅是装逼更是一种趋势
首先对UIButton重写

#import <UIKit/UIKit.h>

typedef void (^ButtonBlock)(UIButton *);

@interface UIButton (Block)
-(void)setButtonEvents:(UIControlEvents )events withBlock:(ButtonBlock)block;
@end
#import "UIButton+Block.h"
#import <objc/runtime.h>

static char * const BBLOCK = "bblock";
@implementation UIButton (Block)
-(void)setButtonEvents:(UIControlEvents )events withBlock:(ButtonBlock)block{
    objc_setAssociatedObject(self, BBLOCK, block,  OBJC_ASSOCIATION_COPY_NONATOMIC);
    [self addTarget:self action:@selector(blockAction) forControlEvents:events];
}
-(void)blockAction{
    ButtonBlock bblock = objc_getAssociatedObject(self, BBLOCK);
    if (bblock) {
        bblock(self);
    }
}
@end

然后就是使用了 。。。

UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(50, 50, 100, 100);
button.backgroundColor = [UIColor redColor];
button.tag = 777;
[button setButtonEvents:UIControlEventTouchUpInside withBlock:^(UIButton *but) {
    }];
[self.view addSubview:button];

3.使用objc_msgSend()调用方法

直接上代码

#import "ViewController.h"
#import "UIButton+Block.h"
#import <objc/message.h>

@interface ViewController ()<UIAlertViewDelegate>
@end
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *button = [[UIButton alloc] init];
    button.frame = CGRectMake(50, 50, 100, 100);
    button.backgroundColor = [UIColor redColor];
    button.tag = 777;
    [button setButtonEvents:UIControlEventTouchUpInside withBlock:^(UIButton *but) {

    }];
    [self.view addSubview:button];

    SEL sel = @selector(setBackgroundColor:);
    UIColor *color = [UIColor greenColor];
    objc_msgSend(button,sel,color);

}

注意需要导入的头文件,我觉得代码贴出来基本上能看懂,但是需要注意的是当你把这段代码复制到编译器中,编译器会报错
这里写图片描述

需要做一些设置,修改下几个xcode的几个参数
这里写图片描述

把YES都换成NO 就可以了 。。。。
objc_msgSend的作用是让一个对象发消息;第一个参数就是对象本身,第二个就是SEL也就是方法,第三个就是该方法需要的值咯,我们不看API我们可以猜想这个肯定是个变参的方法 。。。。。 但是我们就点到为止

4.方法交换

runtime可以实现方法交换 ,先来一段简单的代码 。。。

- (void)viewDidLoad {
    [super viewDidLoad];
    [self function1];
}
-(void)function1{
    NSLog(@"this is function1");
}
-(void)function2{
     NSLog(@"this is function222222");
}

毋庸置疑 输出肯定是 : this is function1
那么如何才能输出 this is function222222 ? 这貌似有点天方夜谭,但是借助runtime 其实是可以实现的 。。。。

#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self function1];
    [ViewController staticfunction3];
}
+(void)load{
    SEL sel1 = @selector(function1);
    SEL sel2 = @selector(function2);
    Method m1 = class_getInstanceMethod(self , sel1);
    Method m2 = class_getInstanceMethod(self, sel2);
    method_exchangeImplementations(m1, m2);

    SEL sel3 = @selector(staticfunction3);
    SEL sel4 = @selector(staticfunction4);
    Method m3 = class_getClassMethod(self , sel3);
    Method m4 = class_getClassMethod(self, sel4);
    method_exchangeImplementations(m3, m4);
}
-(void)function1{
    NSLog(@"this is function1");
}
-(void)function2{
     NSLog(@"this is function222222");
}

+(void)staticfunction3{
    NSLog(@"static this is function 3333333");
}
+(void)staticfunction4{
    NSLog(@"static this is function  4444444");
}

2017-10-10 18:10:50.429555+0800 runtime[27274:7682773] this is function222222
2017-10-10 18:10:50.429607+0800 runtime[27274:7682773] static this is function  4444444

注意的是 +(void)load 方法交换需要在这个里面搞
然后注意类方法和对象方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值