码迷,mamicode.com
首页 > 其他好文 > 详细

IMP的简单使用

时间:2015-07-21 01:11:42      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:

什么是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

 

 

IMP的简单使用

标签:

原文地址:http://www.cnblogs.com/guozhong/p/4663087.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!