标签:
什么是IMP指针呢?
IMP其实就是Implementation的缩写,指向一个方法实现的指针,每一个方法都有一个对应的IMP;
调用一个IMP的方式和调用普通C函数相同,比如: id returnObjc = someIMP(objc,SEL,params...);
IMP指针有什么作用呢?
假如有这样一种应用场景,有许多个ViewController,我想在对项目改动最小的情况下,在当每个Controller执行完ViewDidLoad以后就在控制台把自己的名字打印出来,方便我去做调试或者了解项目结构,最直接的方式是让所有的控制器继承BaseViewController,但这样做太高耦合,而且维护成本太高,
方法1:利用Runtime 的Method Swizzling实现:(给控制器添加分类)
#import "UIViewController+viewDidLoad.h"
#import <objc/runtime.h>
@implementation UIViewController (viewDidLoad)
+ (void)load {
// 一次性执行
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 获取原来的方法
Method viewDidLoad = class_getInstanceMethod(self, @selector(viewDidLoad));
// 新增的方法
Method viewDidLoaded = class_getInstanceMethod(self, @selector(viewDidLoaded));
// 交换两个方法的实现
method_exchangeImplementations(viewDidLoad,viewDidLoaded);
});
}
/**
* 用于交换的方法
*/
- (void)viewDidLoaded {
// 执行原来的方法 保证不改变原来的操作
[self viewDidLoaded];
// 在保证原有代码执行后增加额外的代码
NSLog(@"%@", NSStringFromClass([self class]));
}
测试:
#import "ViewController.h"
#import "UIViewController+viewDidLoad.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
打印结果:
2015-07-20 23:08:18.511 IMP[54316:702928] ViewController
方法2:利用IMP指针实现
#import "UIViewController+viewDidLoad.h"
#import <objc/runtime.h>
/*定义一个和有参数的IMP指针相同的指针类型,在获取IMP时把它强转为此类型。这样运用IMP指针后,就不需要额外的给ViewController写新的方法:
*/
/**
还有一个地方我们需要注意,如果这样直接调用IMP的话就会发生经典的EXC_BAD_ACCESS错误,我们定义的IMP指针是一个有返回值的类型,而其实我们获取的viewDidLoad这个方法是没有返回值的,所以我们需要新定义一个和IMP相同类型的函数指针比如VIMP,把他的返回值定位Void,这样如果你修改的方法有返回值就用IMP,没有返回值就用VIMP。
*/
// 值得注意的是,如果你重写的方法有返回值,不要忘记在最后做return。
typedef id(*_IMP)(id,SEL,...);
typedef void (*_VIMP)(id,SEL,...);
@implementation UIViewController (viewDidLoad)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 获取原始方法
Method viewDidLoad = class_getInstanceMethod(self, @selector(viewDidLoad));
// 获取方法的实现
_VIMP viewDidLoad_VIMP = (_VIMP)method_getImplementation(viewDidLoad);
// 重新设置方法的实现
method_setImplementation(viewDidLoad, imp_implementationWithBlock(^(id target,SEL action ){
// 调用原有方法的实现
viewDidLoad_VIMP(target,@selector(viewDidLoad));
// 新增代码
NSLog(@"%@ did load",[target class] );
}));
});
}
测试:
#import "ViewController.h"
#import "UIViewController+viewDidLoad.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
打印结果:
2015-07-20 23:15:37.233 IMP[54756:708035] ViewController did load
标签:
原文地址:http://www.cnblogs.com/guozhong/p/4663087.html