記錄一次iOS無法獲取topViewController的問題

  • 時間:2019-06-11 02:13 作者:iOS_Yee 來源:iOS_Yee 閱讀:46
  • 掃一掃,手機訪問
摘要:問題關鍵[[UIApplication sharedApplication].keyWindow rootViewController][[[UIApplication sharedApplication] delegate] window].rootViewController問題形容目前接手的項
問題關鍵

[[UIApplication sharedApplication].keyWindow rootViewController]
[[[UIApplication sharedApplication] delegate] window].rootViewController

問題形容

目前接手的項目是一個比較老的項目,界面的跳轉大多數都是利用獲取topViewController的方式。在增加新功能的時候發現topViewController有時不肯定是自己需要的,取到錯誤的情況基本上都是窗口上不止一個UIWindow,基本上分為下面三種情況。

  1. UITextView | UITextField
  2. UIAlertController | UIAlertView | 系統自己的控件
  3. 自己設置的maskView(有新的UIWindow創立)
問題定位

界面跳轉的時候,由于拿到的getTopViewController有時不是理想ViewController,界面無法跳轉,想著可能是方法錯了,在網上檢索,發現用‘遞歸’思想獲取ViewController沒有問題,但是輸出的TopViewController一直不正確,通過打印[[UIApplication sharedApplication].keyWindow rootViewController],結果輸出不是UITabBarViewController。這才發現問題所在。假如換成[[[UIApplication sharedApplication] delegate] window].rootViewController問題就處理了。

獲取topViewController的代碼如下。

+ (UIViewController *)getTopViewController {    UIViewController *resultVC;    //這里的window有時獲得不是delegate的window    //自己可以自行驗證下面兩行代碼的區別。    resultVC = [self _topViewController:[[UIApplication sharedApplication].keyWindow rootViewController]];    resultVC = [[[UIApplication sharedApplication] delegate] window].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;}

在stackoverflow上檢索到這樣一句話: [鏈接見參考]

When they are different, usually you are presenting another window other than the app delegate's main window. Your app can have many windows but only the keyWindow is the window that is visible on the screen and receiving events (example could be a UIAlert when visible and receiving events it is the keywindow) reference:

大概意思就是:
當你的窗口不止一個UIWindow對象時(這個新的window是可見的),keyWindow就不是[[UIApplication sharedApplication] delegate] window.了。

問題實踐

下面的場景驗證,都是打印下面三個Window的內存地址。

  UIWindow  *delegateWindow    = [[[UIApplication sharedApplication] delegate] window];  UIWindow  *keyWindow         = [UIApplication sharedApplication].keyWindow;  UIWindow  *lastObjectWindow  = [UIApplication sharedApplication].windows.lastObject;
  • UITextView | UITextField
    //增加鍵盤監聽,并打印每個時刻的keyWindow對象    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShowNotification:) name:UIKeyboardDidShowNotification object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil];    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];    - (void)keyboardWillShow:(NSNotification*)notification{}    - (void)keyboardDidShowNotification:(NSNotification*)notification{}    - (void)keyboardWillHideNotification:(NSNotification*)notification{}    - (void)keyboardDidHide:(NSNotification*)notification{}
系統版本形容信息
12.0無論是在那個方法,當前打印windows都會有三個Window,UIWindowUITextEffectsWindowUIRemoteKeyboardWindowkeyWindow和delegate window內存地址相同
9.1無論是在那個方法,當前打印windows都會有三個Window,UIWindowUITextEffectsWindow UIRemoteKeyboardWindowkeyWindow和delegate window內存地址相同
8.1無論是在那個方法,當前打印windows都會有三個Window,UIWindowUITextEffectsWindow UIRemoteKeyboardWindowkeyWindow和delegate window內存地址相同
  • UIAlertView | UIAlertController | UIActionSheet
屬性形容信息
UIAlertView_UIAlertControllerShimPresenterWindow,內存地址已經不同 (iOS 8.1
UIActionSheet_UIAlertControllerShimPresenterWindow,內存地址已經不同 (iOS 8.1)
  • maskView

基本上大多數maskView,為了不讓alert視圖或者者keyBoard視圖遮住,基本上都會選擇新建Window,此類方法需要特殊條件才能測試。

    //可自行測試偽代碼,新建Window    UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];    window.windowLevel = UIWindowLevelAlert;    window.rootViewController = viewController;    [window makeKeyAndVisible];
問題總結
  1. 當視圖出現鍵盤輸入操作時,delegate window 和keywindow是不變的
  2. 當出現UIAlertView或者者UIActionSheet等提醒框類視圖時,delegate window 和keywindow已經不一樣,這點需要注意。
  3. 工程出現太多topViewController跳轉時,這種太違反軟件設計準則,反向傳值問題非常大。
  4. 當出現側滑欄這樣的設計時,無論是通過delegate window或者者keywindow,遞歸取值可能就會有問題,還是老老實實找到Super ViewController才是硬道理。
參考鏈接

https://stackoverflow.com/questions/21698482/diffrence-between-uiapplication-sharedapplication-delegate-window-and-u

  • 全部評論(0)
最新發布的資訊信息
【系統環境|】阿里云服務器Centos7搭建pptp VPN 一鍵安裝腳本 親測好用(2020-03-18 02:39)
【系統環境|服務器應用】在CentOS 7上如何安裝Gogs 0.11.53(2020-02-10 10:14)
【系統環境|】淘碼庫,據消息稱已被調查。淘碼庫源碼網,已經無法訪問!(2020-01-14 04:13)
【系統環境|服務器應用】Discuz隱藏后臺admin.php網址修改路徑(2019-12-16 16:48)
【系統環境|服務器應用】2020新網站如何讓百度快速收錄網站首頁最新方法,親測有用!免費(2019-12-16 16:46)
【系統環境|服務器應用】Discuz發布帖子時默認顯示第一個主題分類的修改方法(2019-12-09 00:13)
【系統環境|軟件環境】Android | App內存優化 之 內存泄漏 要點概述 以及 處理實戰(2019-12-04 14:27)
【系統環境|軟件環境】MySQL InnoDB 事務(2019-12-04 14:26)
【系統環境|軟件環境】vue-router(單頁面應用控制中心)常見用法(2019-12-04 14:26)
【系統環境|軟件環境】Linux中的Kill命令(2019-12-04 14:26)
手機二維碼手機訪問領取大禮包
返回頂部
2019白小姐旗袍图库