美文网首页
iOS卡顿 防止多次PUSH一个页面

iOS卡顿 防止多次PUSH一个页面

作者: Onego | 来源:发表于2016-11-11 19:00 被阅读1056次

    iOS卡顿这个问题本身就是个问题,但有这个问题避免不了万一卡了呢。

    在网络少着了很多资料都感觉有些问题,下面是我根据网络上的方案改良一下;

    问题描述:
    当PUSH一个新的ViewController的时候,不管是init的过于臃肿还是耗时操作没有处理,都有可能导致卡顿;
    暴力的测试喜欢狂点,这就出现了同一个ViewController被PUSH了多次

    我通过重写导航控制器的方法来解决这个问题。

    #import <UIKit/UIKit.h>  
      
    @interface YBRNaviViewController : UINavigationController  
      
    @end  
    
    #import "YBRNavigationController.h"
    #import "Aspects.h" //一个可以Hook方法的库
    
    @interface YBRNavigationController ()
    <
    UINavigationControllerDelegate
    >
    {
        BOOL _pushing;
        id<Aspect> _aspect;
    }
    
    @end
    
    @implementation YBRNavigationController
    
    - (instancetype)initWithRootViewController:(UIViewController *)rootViewController
    {
        self = [super initWithRootViewController:rootViewController];
        if (self) {
            self.delegate = self; //默认代理设置Self
        }
        return self;
    }
    
    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    
        //这个地方有个问题,initWithRootViewController会触发pushViewController
        if (self.viewControllers.count == 0) {
            [super pushViewController:viewController animated:animated];
            return;
        }
        
        if (_pushing == YES) {
            NSLog(@"被拦截 %@",viewController);
            return;
        }else {
            NSLog(@"PUSH %@",viewController);
            _pushing = YES;
        }
       [super pushViewController:viewController animated:animated];
    }
    
    - (void)setDelegate:(id<UINavigationControllerDelegate>)delegate {
        [super setDelegate:delegate];
    
        //移除_aspect
        if (_aspect) {
            [_aspect remove];
        }
        
        if (delegate && ![self isEqual:delegate]) {
            //不是Self
            if ([delegate respondsToSelector:@selector(navigationController:didShowViewController:animated:)]) {
                //当delegate已经实现 navigationController:didShowViewController:animated: 的时候,
                //Hook 该方法
                //当然也可以使用 swizzleMethod ,Aspect的API更友好些
                __weak __typeof(self)weakSelf = self;
                _aspect = [((NSObject *)delegate) aspect_hookSelector:@selector(navigationController:didShowViewController:animated:) withOptions:AspectPositionAfter usingBlock:^(id instance, NSArray *args) {
                    [weakSelf navigationController:args[0] didShowViewController:args[1] animated:args[2]];
                } error:nil];
            }else {
                //为delegate动态添加 navigationController:didShowViewController:animated:
                //不知道有没有这方面的库可以用,只能自己写
                Class class = [delegate class];
                
                swizzleMethod(class, @selector(navigationController:didShowViewController:animated:), @selector(navigationController:didShowViewController:animated:));
            }
        }
    }
    
    #pragma mark - UINavigationControllerDelegate
    -(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
        _pushing = NO; //完成PUSH
    }
    
    @end
    
    
    ///黑魔法
    void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
    {
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    
    

    相关文章

      网友评论

          本文标题: iOS卡顿 防止多次PUSH一个页面

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