iOS學習——獲取當前最頂層的ViewController
在iOS開發過程中,我們經常性會需要獲取當前頁面的ViewController,然後利用ViewController進行一些操作,例如在最頂層的ViewController上展示一個UIAlertController,或者在最頂層的ViewController上present另一個ViewController,或者進行其他操作。
1 實現思路
通過最底層的ViewController依次向上尋找,直到找到最頂層的ViewController,也就是從UIApplication的keyWindow的rootViewController開始尋找(如果有多個UIWindow則要考慮UIWindow的選擇問題。
在尋找的過程中,要分別考慮當前ViewController是UITabBarController和UINavigationController的情況,同時還要考慮到當前ViewController是否通過 presentViewController:animated:completion: 模態展示了其他ViewController。
2 實現方法
方法一:
- (UIViewController *)topViewController { UIViewController *resultVC; resultVC = [self _topViewController:[[UIApplication sharedApplication].keyWindow rootViewController]]; while (resultVC.presentedViewController) { resultVC = [self _topViewController:resultVC.presentedViewController]; } return resultVC; } - (UIViewController *)_topViewController:(UIViewController *)vc { if ([vc isKindOfClass:[UINavigationController class]]) { return [self _topViewController:[(UINavigationController *)vc topViewController]]; } else if ([vc isKindOfClass:[UITabBarController class]]) { return [self _topViewController:[(UITabBarController *)vc selectedViewController]]; } else { return vc; } return nil; }
使用方法:
UIViewController *topmostVC = [self topViewController];
方法二:
//獲取當前螢幕顯示的viewcontroller - (UIViewController *)getCurrentVC { UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; UIViewController *currentVC = [self getCurrentVCFrom:rootViewController]; return currentVC; } - (UIViewController *)getCurrentVCFrom:(UIViewController *)rootVC { UIViewController *currentVC; if ([rootVC presentedViewController]) { // 檢視是被presented出來的 rootVC = [rootVC presentedViewController]; } if ([rootVC isKindOfClass:[UITabBarController class]]) { // 根檢視為UITabBarController currentVC = [self getCurrentVCFrom:[(UITabBarController *)rootVC selectedViewController]]; } else if ([rootVC isKindOfClass:[UINavigationController class]]){ // 根檢視為UINavigationController currentVC = [self getCurrentVCFrom:[(UINavigationController *)rootVC visibleViewController]]; } else { // 根檢視為非導航類 currentVC = rootVC; } return currentVC; }
解析:程式碼主要使用了遞迴的思想(哈哈哈,畢業工作半年,發覺第一次寫iOS用到遞迴,突然覺得高大上)。 [UIApplication sharedApplication].keyWindow.rootViewController獲取到的是專案的根檢視,結合可能用到UITabBarController或者UINavigationController作為導航結構,以及可能present出新的VC,其實如果用storyboard的方式寫UI的話就很清晰,類似樹的結構,再利用遞迴找到當前檢視。
ps:
如果是需要push新的檢視,就非常簡單了。用上面的方法獲取到頂層的檢視,判斷currentVC.navigationController是否為nil。(為nil,則新建UINavigationController,然後再push;否則直接用currentVC.navigationController去push)。
三 擴充套件
如果用到的場景主要是vc裡,可以弄成類別如下:
#import "UIViewController+Helper.h"
@property (nonatomic, strong ,readonly) UIViewController * _Nullable currentVC;
//當前螢幕顯示的viewcontroller
-(UIViewController *)currentVC{
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *controller = [self getCurrentVCFrom:rootViewController];
return controller;
}
//getCurrentVCFrom參考上文兩種方法