这篇博文是我的另一篇 Aspects源码剖析中的一部分,考虑到这部分内容相对独立,单独成篇以便查询。 在Objective-C中调用一个方法,其实是向一个对象发送消息。每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向Method具体的实现。


具体实现代码如下:
代码来源: https://github.com/hejunm/iOS-Tools
@implementation HJMSwizzleTools:NSObject
+ (void)hjm_swizzleWithClass:(Class)processedClass originalSelector:(SEL)originSelector swizzleSelector:(SEL)swizzlSelector{
Method originMethod = class_getInstanceMethod(processedClass, originSelector);
Method swizzleMethod = class_getInstanceMethod(processedClass, swizzlSelector);
//当processedClass实现originSelector时,didAddMethod返回false,否则返回true. 如果当前类没有实现originSelector而父类实现了,这是直接使用method_exchangeImplementations会swizzle父类的originSelector。这样会出现很大的问题。
BOOL didAddMethod = class_addMethod(processedClass, originSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
if (didAddMethod) {
class_replaceMethod(processedClass, swizzlSelector, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
}else{
method_exchangeImplementations(originMethod, swizzleMethod);
}
}
@end
可以这样使用
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[HJMSwizzleTools hjm_swizzleWithClass:self originalSelector:@selector(viewDidLoad) swizzleSelector:@selector(swizzleViewDidLoad)];
});
}
//被替换了。。
- (void)viewDidLoad {
[super viewDidLoad];
}
//现在系统会调用这个方法
- (void)swizzleViewDidLoad {
NSLog(@"do something");
}