runtime
中类似@selector(coding)
这样的是函数名;类似(IMP)coding
才是函数执行体的入口指针。
将函数分为函数名和函数执行体两部分,就带来了很大的灵活性;
class_getInstanceMethod
这个函数可以通过函数名得到对应的函数执行体;
method_exchangeImplementations
这个函数可以交换两个函数的执行体;
-
本来函数名和函数执行体是一一对应的,很好理解;
-
如果执行一次
method_exchangeImplementations
,交换了两个函数的执行体,那么函数名和函数执行体就错位了;会显得很奇怪; -
如果再执行一次
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];
}
测试一下
- 正常状态
- 交换状态
网友评论