下面两种实现是在iOS开发中最常用的方法交换方式,那么两种实现方式具体有什么区别呢?
首先,以上两种实现都可以达到方法交换的效果,但是方案二在某些情况下会发生崩溃,而方案一相对安全一些。
方案一:
+ (void)swizzleInstanceMethod:(SEL)originalSel with:(SEL)swizzledSel {
Method originalMethod = class_getInstanceMethod(self, originalSel);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSel);
BOOL didAddMethod =
class_addMethod(self,
originalSel,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(self,
swizzledSel,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
方案二:
+ (void)swizzleInstanceMethod:(SEL)originalSel with:(SEL)swizzledSel {
Method originalMethod = class_getInstanceMethod(self, originalSel);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSel);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
- 假设有两个A、B两个类,B是A的子类,
@interface A : NSObject
@end
@implementation A
- (void)test {
NSLog(@"test");
}
@end
@interface B : A
@end
@implementation B
- (void)btest {
[self btest];
NSLog(@"btest");
}
@end
- 然后交换B类的方法
[self swizzleInstanceMethod:@selector(test) with:@selector(btest)];
此时A类的实例调用test
方法,就会发生崩溃。
因为 btest
方法是属于B类的,那么当[self btest]
代码执行时,会发生unrecognized selector
错误
由于B类未实现test
方法,所以其实交换的是父类的方法,才导致了崩溃。
而第二种方案,首先会为B类添加test
方法,如果添加失败,说明B类已经实现了此方法,那么直接交换是没有问题的,如果添加成功说明,B类并没有实现test
方法,那么此时只需要替换目标方法的实现就可以了。
网友评论