Method Swizzling 原理(方法搅拌?)

前言

如果使用恰当,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);  

Method Swizzling 的封装
——————–

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类方法会默认从父类开始调用。

版权

发布了456 篇原创文章 · 获赞 310 · 访问量 40万+

猜你喜欢

转载自blog.csdn.net/u011018979/article/details/78019668