Runtime方法交换-2021-02-24-周三

2021-02-25  本文已影响0人  勇往直前888

runtime中类似@selector(coding)这样的是函数名;类似(IMP)coding才是函数执行体的入口指针。
将函数分为函数名和函数执行体两部分,就带来了很大的灵活性;

class_getInstanceMethod这个函数可以通过函数名得到对应的函数执行体;

method_exchangeImplementations这个函数可以交换两个函数的执行体;

给Person添加两个方法

// 写代码
- (void)coding {
    NSLog(@"小明在写代码");
}

// 吃饭
- (void)eating {
    NSLog(@"小明在吃饭");
}

做个测试界面

image.png

方法交换

// 执行交换
- (void)change {
    Method codingMethod = class_getInstanceMethod(self.person.class, @selector(coding));
    Method eatingMethod = class_getInstanceMethod(self.person.class, @selector(eating));
    method_exchangeImplementations(codingMethod, eatingMethod);
}

这里不管函数名和函数执行体是否对应,反正就交换一次

状态记忆

@interface ExchangeViewController ()

// 交换按钮,记忆按钮的状态
@property (weak, nonatomic) IBOutlet UISwitch *exchangeSwitch;

@property (strong, nonatomic) Person *person;

// 记忆是否交换过
@property (assign, nonatomic) BOOL isChanged;

@end

交换按钮的状态;是否交换过,这两个状态是需要记忆的

按钮响应

#pragma mark - action
// 根据记忆状态,交换函数执行体
- (IBAction)exchangeSwitchChanged:(id)sender {
    // 还没有交换过,并且要求交换;那么交换一次
    if ((self.exchangeSwitch.isOn) && !self.isChanged) {
        [self change];
        self.isChanged = YES;
    }
    
    // 已经交换过,并且要求没交换前的原始函数;那么交换一次,交换回来
    if ((!self.exchangeSwitch.isOn) && self.isChanged) {
        [self change];
        self.isChanged = NO;
    }
}

// 写代码
- (IBAction)writeButtonTouched:(id)sender {
    [self.person coding];
}

// 吃饭
- (IBAction)eatButtonTouched:(id)sender {
    [self.person eating];
}

测试一下

image.png image.png image.png image.png

Demo地址

RuntimeDemo

上一篇下一篇

猜你喜欢

热点阅读