参考资料:
基础原理:
在Objective-c消息是什么一文中,我们知道。类的成员函数在 objc_class结构体中存放在struct objc_method_list **methodLists;的方法列表中。methodLists中Method的定义如下:
typedef struct objc_method *Method;
typedef struct objc_ method {
SEL method_name;
char *method_types;
IMP method_imp;
};
objc_msgSend 会根据方法选标 SEL 在类结构的方法列表中查找方法实现IMP,我们要做的Method Swizzling 就是通过替换不同Method 的IMP来达到交换函数的实现的目的。
一个简单的例子:
定义一个Fish类:
#import <Foundation/Foundation.h>
@interface Fish : NSObject
-(void)fishDescribeYouSelf;
@end
#import "Fish.h"
@implementation Fish
-(void)fishDescribeYouSelf{
NSLog(@"I am fish");
}
@end
再定义一个Flower类:
#import <Foundation/Foundation.h>
@interface Flower : NSObject
-(void)flowerDescribeYouSelf;
@end
#import "Flower.h"
@implementation Flower
-(void)flowerDescribeYouSelf{
NSLog(@"I am flower");
}
@end
method_exchangeImplementations (交换两个函数的实现)的使用
Fish *fish = [[Fish alloc] init];
Method fish_method = class_getInstanceMethod([Fish class], NSSelectorFromString(@"fishDescribeYouSelf"));
Method flower_method = class_getInstanceMethod([Flower class], NSSelectorFromString(@"flowerDescribeYouSelf"));
method_exchangeImplementations(fish_method, flower_method);
[fish fishDescribeYouSelf];
输出:
I am flower
method_exchangeImplementations交换了@SEL fish_method与@SEL flower_method的IMP,所以调用fishDescribeYouSelf的时候输出了I am flower。
class_replaceMethod的使用:
Fish *fish = [[Fish alloc] init];
Method flower_method = class_getInstanceMethod([Flower class], NSSelectorFromString(@"flowerDescribeYouSelf"));
IMP flowerIMP = method_getImplementation(flower_method);
class_replaceMethod([Fish class], NSSelectorFromString(@"fishDescribeYouSelf"), flowerIMP, NULL);
[fish fishDescribeYouSelf];
输出:
I am flower
使用class_replaceMethod替换Fish 中fishDescribeYouSelf的IMP函数指针为Flower的flowerDescribeYouSelf.