iOS 方法交换 method_exchangeImplemen
方法交换
使用方法交换需要注意些什么呢
1、在交换系统方法后要注意结束前调用本方法,也就是执行系统方法
2、再交换前,判断类中是否已经实现了系统方法,没有的话需要增加方法,避免交换父类方法
3、加dispatch_once,只执行一次
方法交换
当我们用如下方法写方法交换的时候,会出现什么问题呢
+ (void)hookClass:(Class)classObject originalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
Method method1 = class_getInstanceMethod(classObject, originalSelector);
Method method2 = class_getInstanceMethod(classObject, swizzledSelector);
method_exchangeImplementations(method1, method2);
}
设想一种情况,想交换UIButton的sendAction方法,用上述方法,实际上交换的是父类的sendAction和UIButton的custom方法,那么当点击其他继承UIControl的类时,比如UISegmentedControl,会出现崩溃,因为调用UISegmentedControl的sendAction调用的是custom方法,但是UISegmentedControl是没有这个custom方法的,就会抛出异常
那么就要增加判断
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method originalMethod = class_getInstanceMethod([self class], @selector(originalMethod));
Method swizzlingMethod = class_getInstanceMethod([self class], @selector(swizzlingMethod));
BOOL isAdded = class_addMethod([self class], method_getName(originalMethod), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
if (isAdded)
{
//添加成功说明方法在原类中不存在,用下面的方法替换其实现");
class_replaceMethod([self class], method_getName(originalMethod), method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod));
}
else
{
NSLog(@"方法在原类中存在,用下面的方法交换其实现方法");
method_exchangeImplementations(originalMethod, swizzlingMethod);
}
});
}
或者
// 这两行与以前没有任何变化
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
//如果本类中,没有此SEL,那就会去父类里找,返回的就是父类里的信息,然后将父类的信息,添加到本类中,就相当于,本类完全的继承了父类的方法,
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
if (didAddMethod) {
//添加成功说明方法在原类中不存在,添加后本类中,已经有一个originalSelector方法了
//
//我们重新获得一下originalMethod,(我们第一次获得originalMethod是返回父类的originalMethod,这次是本类的)
originalMethod = class_getInstanceMethod(class, originalSelector);
}
method_exchangeImplementations(swizzledMethod, originalMethod);
第二种和第三种原理是一样的,只是写法略有不同