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

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

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

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

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

#import   
  
@interface YBRNaviViewController : UINavigationController  
  
@end  
#import "YBRNavigationController.h"
#import "Aspects.h" //一个可以Hook方法的库

@interface YBRNavigationController ()
<
UINavigationControllerDelegate
>
{
    BOOL _pushing;
    id _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)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一个页面)