iOS中IMP指针的运用

iOS中若是对Runtime有必定了解的话,必定据说过或者用过这个函数 
void method_exchangeImplementations(Method m1, Method m2),它一般就是所说的method swizzling,算是ObjC的”黑魔法”了,做用就是在程序运行期间动态的给两个方法互换实现;ios

好比: 
程序中有许多个ViewController,我想在对项目改动最小的状况下,在当每一个Controller执行完ViewDidLoad之后就在控制台把本身的名字打印出来,方便去作调试或者了解项目结构函数

其实咱们的目的就是重写ViewDidLoad的方法,并在他的方法最后加上几句Log,因此咱们须要给UIViewController创建一个category,由于咱们知道,若是在Catagory中重写一个方法,就会覆盖它的原有方法实现,可是,这样作之后就没有办法调用系统原有的方法,由于在一个方法里调用本身的方法会是一个死循环。因此咱们的解决办法就是,另外写一个方法来和viewDidLoad“交换”,这样外部调用viewDidLoad就会调到新建的这个方法中,一样,咱们调用新建的方法就会调用到系统的viewDidLoad中了spa

第一种方案:.net

#import "UIViewController+viewDidLoad.h"
#import <objc/runtime.h>

@implementation UIViewController (viewDidLoad)

+ (void)load
{
    //保证交换方法只执行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        //获取这个类的viewDidLoad方法,它的类型是一个objc_moethod结构体的指针
        Method viewDidLoad = class_getInstanceMethod(self, @selector(viewDidLoad));

        //获取自定义的方法
        Method viewDidLoaded = class_getInstanceMethod(self, @selector(viewDidUnload));

        //互换两个方法实现
        method_exchangeImplementations(viewDidLoad, viewDidLoaded);

    });
}

//新建一个方法与viewDidload交换
- (void)viewDidLoaded
{
    [self viewDidLoaded];

    NSLog(@"%@ did load",self);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

第二种方案:指针

IMP 它是一个指向方法实现的指针,每个方法都一个对应的IMP指针。咱们能够直接调用方法的IMP指针,来避免方法调用死循环的问题调试

//修改的方法有返回值就用IMP,无返回值就用VIMP
typedef id   (*_IMP)  (id,SEL,...);
typedef void (*_VIMP) (id,SEL,...);

#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));

        //获取方法实现
        _VIMP viewDidLoad_IMP = (_VIMP)method_getImplementation(viewDidLoad);

        //从新设置方法实现
        method_setImplementation(viewDidLoad,imp_implementationWithBlock(^(id target,SEL action){
            viewDidLoad_IMP(target,@selector(viewDidLoad));

            //自定义代码
            NSLog(@"%@ did load",target);
        }));
    });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

须要注意事项

修改的方法有返回值就用IMP,没有返回值就用VIMP。重写的方法有返回值,不要忘记在最后作returncode

实际上直接调用一个方法的IMP指针的效率是高于调用方法自己的,若是有一个合适的时机获取到方法的IMP的话,能够试着调用IMP而不用调用方法。get

相关文章
相关标签/搜索