大部分内容参考(复制)自 此文章
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method oriMethod = class_getInstanceMethod(self, @selector(doInstance));
Method swiMethod = class_getInstanceMethod(self, @selector(fx_doInstance));
/// 子类如果实现了父类中要替换的方法, 通过`class_addMethod`是会失败并返回false的.
BOOL didAddMethod = class_addMethod(self, @selector(doInstance), method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
if (didAddMethod) {
/// 添加成功表示当前子类并没有实现父类的'doInstance'方法, 添加完之后'doInstance' SEL
/// 指向swiMethod的IMP, 此时调用'doInstance'的效果和调用'fx_doInstance'效果一样,
/// 因此需要把fx_doInstance的方法实现替换成oriMethod IMP, 这样才能完成替换
class_replaceMethod(self, @selector(fx_doInstance), method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
} else {
/// 添加失败表示当前子类已经重写了父类的'doInstance'方法, 此时, 可以直接替换两个方法的实现.
method_exchangeImplementations(oriMethod, swiMethod);
}
});
}
-
以下是原文的解释, 结合注释来看应该会更容易理解.
-
通过
class_addMethod给Class添加方法(class_addMethod不会取代本类中已存在的实现,只会覆盖本类中继承父类的方法实现- 取得新方法
swiMethod的实现和方法类型 - 往方法名
@selector(fx_doInstance)添加方法 class_addMethod把新方法实现放到旧方法名中,此刻调用doInstance就是调用fx_doInstance,但是调用fx_doInstance会崩溃
- 取得新方法
-
根据
didAddMethod判断是否添加成功- 添加成功说明之前本类没有实现——
class_replaceMethod替换方法 - 添加失败说明之前本类已有实现——
method_exchangeImplementations交换方法 class_replaceMethod用doInstance方法实现替换掉fx_doInstance中的方法实现
- 添加成功说明之前本类没有实现——