美文网首页
iOS获取当前显示控制器

iOS获取当前显示控制器

作者: aspmcll | 来源:发表于2018-04-14 00:53 被阅读0次

    主要思路是通过runtime拦截系统三个转场
    1.拦截tab的setSelectedViewController

    @implementation UITabBarController (VCChangeMethod)
    
    + (void)load {
        [self exchangeInstanceMethod1:@selector(setSelectedViewController:) method2:@selector(vc_setSelectedViewController:)];
    }
    
    - (void)vc_setSelectedViewController:(__kindof UIViewController *)selectedViewController {
        [UIApplication sharedApplication].currentVC = selectedViewController;
        [self vc_setSelectedViewController:selectedViewController];
    }
    @end
    

    2.拦截ctr的present和dismiss

    @implementation UIViewController (VCChangeMethod)
    
    + (void)load {
        [self exchangeInstanceMethod1:@selector(presentViewController:animated:completion:) method2:@selector(vc_presentViewController:animated:completion:)];
        [self exchangeInstanceMethod1:@selector(dismissViewControllerAnimated:completion:) method2:@selector(vc_dismissViewControllerAnimated:completion:)];
    }
    
    - (void)vc_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
        [UIApplication sharedApplication].currentVC = viewControllerToPresent;
        [self vc_presentViewController:viewControllerToPresent animated:flag completion:completion];
    }
    
    - (void)vc_dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
        [UIApplication sharedApplication].currentVC = self.presentingViewController;
        [self vc_dismissViewControllerAnimated:flag completion:completion];
    }
    
    @end
    

    3.拦截navc的push和pop

    @implementation UINavigationController (VCChangeMethod)
    + (void)load {
        [self exchangeInstanceMethod1:@selector(pushViewController:animated:) method2:@selector(vc_pushViewController:animated:)];
        [self exchangeInstanceMethod1:@selector(popViewControllerAnimated:) method2:@selector(vc_popViewControllerAnimated:)];
        [self exchangeInstanceMethod1:@selector(popToRootViewControllerAnimated:) method2:@selector(vc_popToRootViewControllerAnimated:)];
        [self exchangeInstanceMethod1:@selector(popToViewController:animated:) method2:@selector(vc_popToViewController:animated:)];
        
    }
    
    - (void)vc_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
        [UIApplication sharedApplication].currentVC = viewController;
        [self vc_pushViewController:viewController animated:animated];
    }
    
    - (UIViewController *)vc_popViewControllerAnimated:(BOOL)animated {
        if (self.viewControllers.count >= 2) {
              [UIApplication sharedApplication].currentVC = self.viewControllers[self.viewControllers.count - 2];
        } else
            [UIApplication sharedApplication].currentVC = self.viewControllers[0];
        return [self vc_popViewControllerAnimated:animated];
    }
    
    - (NSArray<UIViewController *> *)vc_popToRootViewControllerAnimated:(BOOL)animated {
        [UIApplication sharedApplication].currentVC = self.viewControllers[0];
        return [self vc_popToRootViewControllerAnimated:animated];
    }
    
    - (NSArray<UIViewController *> *)vc_popToViewController:(UIViewController *)viewController animated:(BOOL)animated {
        [UIApplication sharedApplication].currentVC = viewController;
       return [self vc_popToViewController:viewController animated:animated];
    }
    
    @end
    

    currentVC通过关联对象注入到UIApplication中
    项目地址:https://github.com/jsonsnow/CLCurrentVC.git

    另一种方法是通过递归当前控制器层级结构获得顶层控制器,该方法存在一个问题,主要体现在dismiss转场上,向一个控制器发送dismiss消息,当前控制器并不会立马从当前层级移除,是一个异步过程,即使不给动画一样存在,dismiss后通过递归获取顶层控制器会获得的是一个将要被dismiss的,拿该控制器去推或present将获得一个错误。
    题外话,一个业务原则当一个控制器销毁的时候先调用其dismiss或pop再进行回调,即,先结束该流程,在处理后续事情,防止上一个流程对后续流程有影响。而且通过运行时来获取栈顶控制器也必须这样做。

    相关文章

      网友评论

          本文标题:iOS获取当前显示控制器

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