前言
如果使用恰当,Method swizzling 还是很安全的.一个简单安全的方法是,仅在load中swizzle。
这里写链接内容Objective-C的hook方案
在Objective-C中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用Objective-C的动态特性,可以实现在运行时偷换selector对应的方法实现,达到给方法挂钩的目的。
每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的Method实现。
针对selector的hook
我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP,
我们可以利用 class_replaceMethod 来修改类,
我们可以利用 method_setImplementation 来直接设置某个方法的IMP,
……
归根结底,都是偷换了selector的IMP
举个例子
#import "NSArray+Swizzle.h"
@implementation NSArray (Swizzle)
- (id)myLastObject
{
id ret = [self myLastObject]; //method_exchangeImplementations 之后,执行到这里将是调用LastObject 方法
NSLog(@"********** myLastObject *********** ");
return ret;
}
@end
Method ori_Method = class_getInstanceMethod([NSArray class], @selector(lastObject));
Method my_Method = class_getInstanceMethod([NSArray class], @selector(myLastObject));
method_exchangeImplementations(ori_Method, my_Method);
NSArray *array = @[@"0",@"1",@"2",@"3"];
NSString *string = [array lastObject];
NSLog(@"TEST RESULT : %@",string);
Possible naming conflicts
[cpp] view plain copy
@implementation NSView (MyViewAdditions)
static void MySetFrame(id self, SEL _cmd, NSRect frame);
static void (*SetFrameIMP)(id self, SEL _cmd, NSRect frame);
static void MySetFrame(id self, SEL _cmd, NSRect frame) {
// do custom work
SetFrameIMP(self, _cmd, frame);
}
+ (void)load {
[self swizzle:@selector(setFrame:) with:(IMP)MySetFrame store:(IMP *)&SetFrameIMP];
}
@end
The order of swizzles matters
多个有继承关系的类的对象swizzle时,先从父对象开始。 这样才能保证子类方法拿到父类中的被swizzle的实现。在+(void)load中swizzle不会出错,就是因为load类方法会默认从父类开始调用。