美文网首页
Method Swizzling的使用

Method Swizzling的使用

作者: 不思想者Alex | 来源:发表于2014-11-28 01:13 被阅读1253次

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


    20130718230259187.jpg

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

    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 <objc/runtime.h>
    
    @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 <objc/runtime.h>
    
    @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的使用

          本文链接:https://www.haomeiwen.com/subject/svaetttx.html