iOS獲取當(dāng)前顯示控制器

主要思路是通過runtime攔截系統(tǒng)三個轉(zhuǎn)場
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通過關(guān)聯(lián)對象注入到UIApplication中
項目地址:https://github.com/jsonsnow/CLCurrentVC.git

另一種方法是通過遞歸當(dāng)前控制器層級結(jié)構(gòu)獲得頂層控制器,該方法存在一個問題,主要體現(xiàn)在dismiss轉(zhuǎn)場上,向一個控制器發(fā)送dismiss消息,當(dāng)前控制器并不會立馬從當(dāng)前層級移除,是一個異步過程,即使不給動畫一樣存在,dismiss后通過遞歸獲取頂層控制器會獲得的是一個將要被dismiss的,拿該控制器去推或present將獲得一個錯誤。
題外話,一個業(yè)務(wù)原則當(dāng)一個控制器銷毀的時候先調(diào)用其dismiss或pop再進行回調(diào),即,先結(jié)束該流程,在處理后續(xù)事情,防止上一個流程對后續(xù)流程有影響。而且通過運行時來獲取棧頂控制器也必須這樣做。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容