Method Swizzling的使用

在 Runtime 改变selector所对应的 imp 来达到让原有 method 实现其他功能的目的


Method Swizzling的使用_第1张图片
20130718230259187.jpg

我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP,
我们可以利用 class_replaceMethod 来修改类,
我们可以利用 method_setImplementation 来直接设置某个方法的IMP,
……
归根结底,都是偷换了selector的IMP,如下图所示

Method Swizzling的使用_第2张图片
20130718230430859.png

相关博客
http://blog.csdn.net/yiyaaixuexi/article/details/9374411

实战:
因为替换了 UINavigationBar 原来的按钮,导致tableView自带的滑动交互无法使用,但是可以通过interactivePopGestureRecognizer来手动设置

- (void)viewDidLoad
{
    [super viewDidLoad];

        if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.delegate = self;
    }
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:YES];
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
    }
}

但是为了防止快速滑动的过程中,多个页面响应了interactivePopGestureRecognizer,从而发生错误,所以要在华东过程中关闭interactivePopGestureRecognizer的响应self.interactivePopGestureRecognizer.enabled = NO,但是overridepushViewController:animated:不起作用,所以想在pushViewController:animated:runtime 中替换成包含相关额外语句的方法.

#import "UINavigationController+Swizzle.h"
#import 

@implementation UINavigationController (Swizzle)


+ (void)load
{

   //只进行一次操作,保证线程安全
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        //获取原有方法
        Method orig_Method = class_getInstanceMethod([UINavigationController class], @selector(pushViewController:animated:));
        //获取修改后的方法
        Method my_Method = class_getInstanceMethod([UINavigationController class], @selector(myPushViewController:animated:));
        //交换
        method_exchangeImplementations(orig_Method, my_Method);
    });
}



- (void)myPushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.enabled = NO;
    }
    
    [self myPushViewController:viewController animated:animated];
}

@end

这样就 OK 了

下面是Github 上封装好的方法

#import "RNSwizzle.h"
#import 

@implementation NSObject (RNSwizzle)

+ (IMP)swizzleSelector:(SEL)origSelector
               withIMP:(IMP)newIMP {
    Class class = [self class];
    Method origMethod = class_getInstanceMethod(class,
                                                origSelector);
    IMP origIMP = method_getImplementation(origMethod);
    
    if(!class_addMethod(self, origSelector, newIMP,
                        method_getTypeEncoding(origMethod)))
    {
        method_setImplementation(origMethod, newIMP);
    }
    
    return origIMP;
}

@end

RNSwizzle使用

    id block = ^NSString*(){
        
        return @"********* YES it works *********";
    };
    
    IMP myIMP = imp_implementationWithBlock(block);
    [NSArray swizzleSelector:@selector(lastObject) withIMP:myIMP];
    
    NSArray *array = @[@"0", @"1", @"2", @"3"];
    NSString *string = [array lastObject];
    NSLog(@"Test request: %@", string);

结果:

2014-08-21 18:05:22.424 Test[22289:60b] Test request: ********* YES it works *********

你可能感兴趣的:(Method Swizzling的使用)