标准的写法
+ (void)load {
Method oldM = class_getInstanceMethod([self class], @selector(test));
Method newM = class_getInstanceMethod([self class], @selector(test_new));
IMP oldIMP = method_getImplementation(oldM);
IMP newIMP = method_getImplementation(newM);
BOOL isAddSucceed = class_addMethod([self class], @selector(test), newIMP, method_getTypeEncoding(newM));
if (isAddSucceed) {
class_replaceMethod([self class], @selector(test_new), oldIMP, method_getTypeEncoding(oldM));
}else {
method_exchangeImplementations(oldM, newM);
}
}
好多同学很奇怪为啥要加个 class_addMethod方法
1.打个比方 父类 Person 子类Son
条件:
如果 test方法 只在父类Person只实现,如果子类不实现test
不调用 class_addMethod 方法。
影响:
[son test]; 调用OK 一点问题都没有
但是如果是 [person test]; 就会调用到 son的实现的new_test;
显示不符合逻辑了 这样会把父类Person搞的很坑。
2.防止父类 Person 跟子类 Son 都没有实现test方法 那直接method_exchangeImplementations 实现后 会崩溃
其实更加严禁的方法应该这么写
+ (void)load {
Method oldM = class_getInstanceMethod([self class], @selector(test));
Method newM = class_getInstanceMethod([self class], @selector(test_new));
IMP oldIMP = method_getImplementation(oldM);
IMP newIMP = method_getImplementation(newM);
BOOL isAddSucceed = class_addMethod([self class], @selector(test), newIMP, method_getTypeEncoding(newM));
if (isAddSucceed) {
// 如果 class_addMethod 成功了,说明之前 fromClass 里并不存在 originSelector,所以要用一个空的方法代替它,以避免 class_replaceMethod 后,后续 toClass 的这个方法被调用时可能会 crash
oldIMP = oldIMP ?: imp_implementationWithBlock(^(id selfObject) {});
const char *oldTypeEncoding = method_getTypeEncoding(oldM) ?: "v@:";
class_replaceMethod([self class], @selector(test_new), oldIMP, oldTypeEncoding);
}else {
method_exchangeImplementations(oldM, newM);
}
}