我们常用的swizzle用法如下:
BOOL simple_Swizzle(Class aClass, SEL originalSel,SEL swizzleSel){
Method originalMethod = class_getInstanceMethod(aClass, originalSel);
Method swizzleMethod = class_getInstanceMethod(aClass, swizzleSel);
method_exchangeImplementations(originalMethod, swizzleMethod);
return YES;
}
BOOL best_Swizzle(Class aClass, SEL originalSel,SEL swizzleSel){
Method originalMethod = class_getInstanceMethod(aClass, originalSel);
Method swizzleMethod = class_getInstanceMethod(aClass, swizzleSel);
BOOL didAddMethod = class_addMethod(aClass, originalSel, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
if (didAddMethod) {
class_replaceMethod(aClass, swizzleSel, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}else{
method_exchangeImplementations(originalMethod, swizzleMethod);
}
return YES;
}
我们分别用这俩种方法来测试下面的3中情况
swizzle一个父类的方法
我们新建一个Father类
@interface Father : NSObject
- (void)work;
@end
@implementation Father
- (void)work{
NSLog(@"father work");
}
@end
Son类
@interface Son : Father
@end
@implementation Son
@end
simple_Swizzle
+ (void)load{
simple_Swizzle(self,@selector(work), @selector(son_work));
}
- (void)son_work{
NSLog(@"son_category work") ;
[self son_work];
}
调用[[Father new] work]
报错
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Father son_work]: unrecognized selector sent to instance 0x60c0000140a0'
分析:
由于class_getInstanceMethod
方法回去父类里面寻找, 最后找到父类的方法,因为我们做了交换,所以父类的方法已经被交换son_work
,而父类里面没有实现son_work
best_Swizzle
由于第二种方法在子类里面add了一个方法,所以交换正常。
swizzle一个不存的方法
我们将Father
类work
的具体实现去掉,然后使用上面俩个方法来测试swizzle
simple_Swizzle
报错
'NSInvalidArgumentException', reason: '-[Son work]: unrecognized selector sent to instance 0x60c000006e40'
分析:
由于class_getInstanceMethod
方法会找不到,返回nil。所以method_exchangeImplementations
会失败,保持原样。所以最后仍然会找不到方法。
best_Swizzle
会循环调用son_work
。
分析:
由于class_getInstanceMethod
方法会找不到,返回nil。这时add也不可能成功,最后交互也会失败,所以最后这种写法就变成了循环调用。
- (void)son_work{
NSLog(@"son_category work") ;
[self son_work];
}
swizzle 不同class的俩个方法
如果我们把Father
的work
方法和animal
方法交换,考虑下下面的代码。
- (void)animal_wrok{
NSLog(@"animal work");
// 这时如果访问self 的变量, 方法会怎么样?
}
网友评论