IOS |无法更改应用程序委托中的根视图控制器

IOS | Unable to change root view controller in app delegate

我正在构建一个应用程序,如果用户已登录,则必须更改其根视图控制器。如果用户已登录,如果用户未登录,我必须将选项卡栏控制器显示为主屏幕,我必须展示一个身份验证控制器。我的两个控制器都是故事板控制器。现在在我的应用程序委托中,我输入了以下代码

        window = UIWindow(frame: UIScreen.main.bounds)

        if UserDefaults.standard.bool(forKey: Constants.UserDefaultsKeys.isLoggedIn){
            initialViewController = storyboard.instantiateViewController(identifier: Constants.StoryBoards.homeViewController) as! TabController
        }else{
            initialViewController = storyboard.instantiateViewController(identifier: Constants.StoryBoards.authenticationController)
        }
        window?.rootViewController = initialViewController
        window?.makeKeyAndVisible()

根据代码,如果用户已登录,TabController 必须是 showed.But 它不是 shown.I 已尝试调试并且 TabControllerviewDidLoad 正在被调用,但我的 authenticationController 仍在显示,这可能是因为 authenticationController 被设置为情节提要中的初始 viewcontroller。谁能帮我解决这个问题

如果您只定位 iOS 13+,您唯一需要做的更改是添加一行:

    window?.rootViewController = initialViewController

    // add this line
    self.window = window

    window?.makeKeyAndVisible()

如果你想支持更早的 iOS 版本,这里是一个完整的 SceneDelegate / AppDelegate 实现:

SceneDelegate.swift

//
//  SceneDelegate.swift
//  Created by Don Mag on 3/27/20.
//

import UIKit

// entire class is iOS 13+
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        print("Scene Delegate willConnectTo", UserDefaults.standard.bool(forKey: "isLoggedIn"))

        guard let windowScene = (scene as? UIWindowScene) else { return }
        let window = UIWindow(frame: windowScene.coordinateSpace.bounds)
        window.windowScene = windowScene

        if UserDefaults.standard.bool(forKey: "isLoggedIn") {
            guard let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomeVC") as? TabController else {
                fatalError("Could not instantiate HomeVC!")
            }
            window.rootViewController = vc
        } else {
            guard let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AuthVC") as? AuthViewController else {
                fatalError("Could not instantiate HomeVC!")
            }
            window.rootViewController = vc
        }

        self.window = window

        window.makeKeyAndVisible()
    }

}

AppDelegate.swift

//
//  AppDelegate.swift
//  Created by Don Mag on 3/27/20.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window : UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
            if #available(iOS 13, *) {
                // do only pure app launch stuff, not interface stuff
            } else {

                print("App Delegate didFinishLaunching... isLoggedIn:", UserDefaults.standard.bool(forKey: "isLoggedIn"))

                self.window = UIWindow()

                if UserDefaults.standard.bool(forKey: "isLoggedIn") {
                    guard let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomeVC") as? TabController else {
                        fatalError("Could not instantiate HomeVC!")
                    }
                    window?.rootViewController = vc
                } else {
                    guard let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AuthVC") as? AuthViewController else {
                        fatalError("Could not instantiate HomeVC!")
                    }
                    window?.rootViewController = vc
                }

                window?.makeKeyAndVisible()

            }
            return true
    }

    // MARK: UISceneSession Lifecycle

    // iOS 13+ only
    @available(iOS 13.0, *)
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }
    // iOS 13+ only
    @available(iOS 13.0, *)
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
    }

}

这是一种将 UIWindow(以及对 rootViewController 的访问权限)扩展到视图控制器的方法,可以更轻松地在整个应用程序中更改 rootviewcontroller:

extension UIViewController {
    var appDelegate: AppDelegate {
    return UIApplication.shared.delegate as! AppDelegate
}

var sceneDelegate: SceneDelegate? {
    guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
        let delegate = windowScene.delegate as? SceneDelegate else { return nil }
     return delegate
}}
   





extension UIViewController {   
        var window: UIWindow? {
            if #available(iOS 13, *) {
                guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
                    let delegate = windowScene.delegate as? SceneDelegate, let window = delegate.window else { return nil }
                       return window
            }
            
            guard let delegate = UIApplication.shared.delegate as? AppDelegate, let window = delegate.window else { return nil }
            return window
        }
    }