iOS 13中获取根视图控制器的正确方法是什么?

3
class TopViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //Code Block 1
        let controller = getTopController()
        print(controller)// Prints out MyTestProject.TopViewController

        //Code Block 2
        let controller2 = getRootController()
        print(controller2)//Prints out nil , because keywindow is also nil upto this point.

        //Code Block 3
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) {
            let controller2 = self.getRootController()
            print(controller2)// Prints out MyTestProject.TopViewController   
        }
    }

    func getTopController() -> UIViewController? {
        guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
            let sceneDelegate = windowScene.delegate as? SceneDelegate else {
                return nil
        }
        return sceneDelegate.window?.rootViewController
    }

    func getRootController() -> UIViewController? {
        let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
        let topController = keyWindow?.rootViewController
        return topController
    }
}

自iOS 13以来,有两种方法可以获取应用程序当前活动/顶部视图控制器。这里:getTopController()和getRootController()显示了这两种方法。
如代码中所述,除了print()结果之外,两者的结果是不同的。
在代码块2中:getRootController无法找到窗口,因此打印出nil。为什么会发生这种情况?
另外,在iOS 13中获得参考最高控制器的全面方法是什么?我现在感到困惑了。
2个回答

1
问题在于当您的视图控制器调用viewDidLoad时,window.makeKey()尚未被调用。
一个可能的解决方法是,在没有可用的关键窗口时,获取windows数组中的第一个窗口。
    func getRootController() -> UIViewController? {
        let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) ?? UIApplication.shared.windows.first
        let topController = keyWindow?.rootViewController
        return topController
    }

请注意,这将解决您的问题,但在窗口变为关键窗口之前,请推迟任何涉及使用关键窗口的操作。

但是为什么getTopController()方法不是同样的情况呢?即使在viewDidLoad中调用,Window也不为nil。 - Prajeet Shrestha
1
问题不在于窗口为空,窗口是存在的,但 isKeyWindow 为 false,因为尚未调用 window.makeKey() - Mario

-1
根据UIView的文档,如果视图尚未添加到窗口中(当调用viewDidLoad时),则窗口属性为nil。
请尝试在viewDidAppear中访问它。
override func viewDidAppear(_ animated: Bool) {
   let controller2 = self.view.window.rootViewController
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接