runtime中方法交换的经典代码如下,其中的class_addMethod和class_replaceMethod怎么理解?
/*
周全起见,有两种情况要考虑一下
第一种情况:要交换的方法并没有在目标类中实现,而是在其父类中实现了, 这时使用class_getInstanceMethod函数获取到的originalSelector指向的就是父类的方法
第二种情况:要交换的方法已经存在于目标类中
*/
BOOL didAdd = class_addMethod(class, oldSel, method_getImplementation(newM), method_getTypeEncoding(newM));
if (didAdd) {
NSLog(@"swizzleInstanceSel * didAdd");
class_replaceMethod(class, newSel, method_getImplementation(oldM), method_getTypeEncoding(oldM));
}
else {
NSLog(@"swizzleInstanceSel * didn'tAdd ----> exchange!");
method_exchangeImplementations(oldM, newM);
}
疑惑:iOS中存在一个方法子类中有父类中没有的case吗?
1、class_addMethod 添加方法
+ (void)load
{
Method method = class_getInstanceMethod([self class], @selector(sayHello));
//添加一个方法personSayHello, 它的实现指向sayHello的实现
BOOL res = class_addMethod([self class], @selector(personSayHello), method_getImplementation(method), method_getTypeEncoding(method));
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:@selector(personSayHello)];
}
- (void)sayHello
{
NSLog(@"say hello");
}
//打印say hello
总结:添加一个方法personSayHello, 它的实现指向sayHello的实现,若目标类已存在该方法的实现就返回NO,什么也不做,若不存在就add一个,相当于一次method_setImplementation
。若直接调用personSayHello方法,会报错unrecognized selector sent to instance
2、class_replaceMethod 替换方法
+ (void)load
{
Method method = class_getInstanceMethod([self class], @selector(sayGoodBye));
class_replaceMethod([self class], @selector(sayHello), method_getImplementation(method), method_getTypeEncoding(method));
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:@selector(sayHello)];
[self performSelector:@selector(sayGoodBye)];
}
- (void)sayHello
{
NSLog(@"say hello");
}
- (void)sayGoodBye
{
NSLog(@"say goodbye");
}
//打印say goodbye、say goodbye
总结:目标类中该方法,不存在时就add,相当于class_addMethod,存在时就replace,相当于method_setImplementation
。返回值表示之前的方法实现。
3、method_exchangeImplementations 交换方法
+ (void)load
{
Method sayGoodsByeMethod = class_getInstanceMethod([self class], @selector(sayGoodBye));
Method sayHelloMethod = class_getInstanceMethod([self class], @selector(sayHello));
method_exchangeImplementations(sayHelloMethod, sayGoodsByeMethod);
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:@selector(sayHello)];
[self performSelector:@selector(sayGoodBye)];
}
- (void)sayHello
{
NSLog(@"say hello");
}
- (void)sayGoodBye
{
NSLog(@"say goodbye");
}
//打印say goodbye、say hello
总结:相当于调用2次method_setImplementation
,俩方法中任意一个方法没有实现都会报错。
总结
回到开始看代码逻辑:当方法不存在,就add再replace,存在就exchange,都是调2次method_setImplementation。
参考:
class_addMethod、class_replaceMethod
iOS中的HOOK技术
class_addMethod实解
网友评论