Runtime-Swizzling方法交换

公司项目开发要用到runtime来hook相应的方法啦,我会在接下来的时间逐渐实践并完善runtime的相关知识,然后分享给大家,也希望大家能指出我的错误。今天先开个坑(頑張れ)
今天就从runtime swizzling开始吧,swizzling方法的主要目的就是hook方法,实现方法的交换,下面的场景为我们交换页面的进入(viewWillAppear)和离开方法(viewWillDisappear)。


swizzling流程图.png

一、首先,我们要创建UIViewController的类别并导入:

#import "UIViewController+Swizzling.h"
#import //导入运行时库

二、在+load方法中调用相应的方法:

//Swizzling应该在+load方法中实现,因为+load方法可以保证在类最开始加载时会调用。runtime影响范围是全局的,以+load能够保证在类初始化的时候一定会被加载,这可以保证统一性。
+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //因为swizzling会改变全局,我们需要在运行时采取相应的防范措施。保证原子操作就是一个措施,确保代码即使在多线程环境下也只会被执行一次。
        [self methodSwizzlingWithOriginalSelector:@selector(viewWillAppear:) bySwizzledSelector:@selector(swizzledViewWillAppear:)];
        
        [self methodSwizzlingWithOriginalSelector:@selector(viewWillDisappear:) bySwizzledSelector:@selector(swizzledViewWillDisappear:)];
    });
}

三、进行方法的交换处理

*
 originalSelector:源方法
 swizzledSelector:我们要交换的方法
 */
+ (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector bySwizzledSelector:(SEL)swizzledSelector{
    Class class = [self class];
    //1、得到类的方法
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    //得到新的类的方法
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    //2、先尝试給源SEL添加IMP,这里是为了避免源SEL没有实现IMP的情况,一般源SEL都是实现的,所以返回NO
    BOOL didAddMethod = class_addMethod(class,originalSelector,
                                        method_getImplementation(swizzledMethod),
                                        method_getTypeEncoding(swizzledMethod));
    NSLog(@"-----------didAddMethod:%@",didAddMethod?@"YES":@"NO");
    /*
     由于源SEL一般都是实现的,万一没有实现,用我们添加的方法替换源SEL。所以,一般直接执行4.
     */
    
    if (didAddMethod) {
        //3、添加成功:说明源SEL没有实现IMP,将源SEL的IMP替换到交换SEL的IMP
        class_replaceMethod(class,swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        //4、添加失败:说明源SEL已经有IMP,直接将两个SEL的IMP交换即可
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

四、在交换方法中实现相应的功能

#pragma mnark 这里是hook的方法,在此处执行。
- (void)swizzledViewWillAppear:(BOOL)animated{
    [self swizzledViewWillAppear:animated];
    //在此处获取当前类的类名
    NSLog(@"进入页面获取当前类名:%@",NSStringFromClass([self class]));
}

- (void)swizzledViewWillDisappear:(BOOL)animated{
    [self swizzledViewWillDisappear:animated];
    NSLog(@"离开页面获取当前类名:%@",NSStringFromClass([self class]));
}

你可能感兴趣的:(Runtime-Swizzling方法交换)