在Objective-C运行时替换类中的方法
原文链接 https://gaoxiaosong.github.io/2014/04/26/replace-class-method.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
我们可以在Objective-C运行时将一个类中的一个方法,动态的替换为该类中的另一个方法。并且在替换后的方法中,依然可以调用以前的方法。
#import <objc/objc-class.h>
void MethodSwizzle(Class aClass, SEL orig_sel, SEL alt_sel)
{
Method orig_method = nil, alt_method = nil;
// First, look for the methods
orig_method = class_getInstanceMethod(aClass, orig_sel);
alt_method = class_getInstanceMethod(aClass, alt_sel);
// If both are found, swizzle them
if ((orig_method != nil) && (alt_method != nil)) {
method_exchangeImplementations(orig_method, alt_method);
}
}
这个替换过程,实际上是将两个方法的实现进行了交换,也就是说原来methodA的方法名字对应methodA的方法实现,但是现在methodA的方法名字对应methodB的方法实现,而methodB的方法名字却对应methodA的方法实现。
iOS和Mac有很多私有的类和函数,令人忧伤的是这些官方都不给用,对于一个开发者来说这是相当纠结的一件事。但如果你知道这个私有方法怎么实现的话呢?完全可以自己改写这些私有类和方法,下面以改写Xcode中的IDEWorkspace这个类的一些方法作为例子来说明一下。
@interface IDEWorkspace (KSImageNamed)
@end
@implementation IDEWorkspace (KSImageNamed)
+ (void)load
{
MethodSwizzle(self, @selector(_updateIndexableFiles:), @selector(swizzle__updateIndexableFiles:));
}
- (void)swizzle__updateIndexableFiles:(id)arg1
{
[self swizzle__updateIndexableFiles:arg1];
// 自定义代码
}
@end
这里我们在load中对于方法进行交换,此时updateIndexableFiles:方法名对应于swizzleupdateIndexableFiles:的方法实现,而swizzleupdateIndexableFiles:方法名却对应于_updateIndexableFiles:的方法实现,故在新的方法中调用[self swizzle_updateIndexableFiles:arg1];实际上进行的是方法名却对应于_updateIndexableFiles:的方法实现过程。