简体   繁体   中英

Swift: Two View Controllers presented

Apologies for the ambiguity of the question; I'll try to explain clearer here.

The Problem

I have some code in AppDelegate.swift that performs conditional navigation; if the user is signed in (and therefore currentUser is not nil ), the app will start in View , a View Controller in the Main storyboard. Else, if the user isn't signed in, the app will start in Welcome , a View Controller in an Auth storyboard.

The following is my code from AppDelegate.swift , ViewController.swift (which is View ), and WelcomeViewController .

Note:

View is the Storyboard ID I set for ViewController ; Welcome is the Storyboard ID I set for WelcomeViewController .

AppDelegate.swift

import UIKit
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        // Configures the Firebase library.
        FirebaseApp.configure()

        // Performs conditional navigation on the condition of currentUser's status.
        self.window = UIWindow(frame: UIScreen.main.bounds)
        let user = Auth.auth().currentUser
        if user != nil {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let rootViewController = storyboard.instantiateViewController(identifier: "View")
            window?.rootViewController = rootViewController
            UIView.animate(withDuration: 0.5) {
                self.window?.makeKeyAndVisible()
            }
        } else {
            let storyboard = UIStoryboard(name: "Auth", bundle: nil)
            let rootViewController = storyboard.instantiateViewController(identifier: "Welcome")
            window?.rootViewController = rootViewController
            UIView.animate(withDuration: 0.5) {
                self.window?.makeKeyAndVisible()
            }
        }

        return true
    }

}

ViewController.swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        print("ViewController presented.")
    }

}

WelcomeViewController.swift

import UIKit

class WelcomeViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        print("WelcomeViewController presented.")
    }

}

Expectations

The app is freshly installed on the Simulator, and therefore there should be no currentUser (and upon debugging, proves to be true). Therefore, I'd expect to see this as the output in the Console:

WelcomeViewController presented.

Instead, this shows up in the Console:

WelcomeViewController presented.
ViewController presented.

Attempts

So far, I thought that the problem might have arised from the fact that Main storyboard is the default Storyboard set since the creation of the project. Therefore, I tried unchecking the 'Initial View Controller' checkbox for the two View Controllers. Just like I'd expected, the following appears instead:

WelcomeViewController presented.
2020-06-20 11:39:38.724658+0800 AppName[11439:237509] [WindowScene] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?

What should I do to make sure that ViewController doesn't appear and replace WelcomeViewController ? All help is appreciated, thanks!

why not set WelcomeViewController as your 'Initial View Controller' and replace its viewDidLoad code with AppDelegate file then:

class WelcomeViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        print("WelcomeViewController presented.")

        let user = Auth.auth().currentUser
        if user != nil {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let rootViewController = storyboard.instantiateViewController(identifier: "View")
            window?.rootViewController = rootViewController
            UIView.animate(withDuration: 0.5) {
                self.window?.makeKeyAndVisible()
            }
        } 
    }

}

you can also look this if you want to set the view controller from AppDelegate:

EDIT: you can use a UINavigationController as your initial view controller as indicated in this answer:

set initial viewcontroller in appdelegate - swift then you just need to set the correct view controller here:

navigationController.viewControllers = [rootViewController]
self.window?.rootViewController = navigationController

Solution

I managed to find the solution to the issue that I'm facing here. There are two mistakes above in the code, and I'll explain it here:

Mistake 1: Code should be in SceneDelegate instead of AppDelegate (iOS 13)

Xcode 11, along with the release of iOS 13, introduced SceneDelegate.swift . I was supposed to put my code above in SceneDelegate.swift instead of AppDelegate.swift ; because I didn't do this, the code hadn't worked as I'd hoped for my Simulator, which was running iOS 13.5.

Here's my rectified code in SceneDelegate.swift :

import UIKit
import Firebase

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }

        // Performs conditional navigation on the condition of currentUser's status.
        let user = Auth.auth().currentUser
        if user != nil {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let rootViewController = storyboard.instantiateViewController(identifier: "View")
            window?.rootViewController = rootViewController
            UIView.animate(withDuration: 0.5) {
                self.window?.makeKeyAndVisible()
            }
        } else {
            let storyboard = UIStoryboard(name: "Auth", bundle: nil)
            let rootViewController = storyboard.instantiateViewController(identifier: "Welcome")
            window?.rootViewController = rootViewController
            UIView.animate(withDuration: 0.5) {
                self.window?.makeKeyAndVisible()
            }
        }
    }

}

Mistake 2 (Important:): Definition of new UIWindow

In my code above, there was a faulty line which caused the creation of a new UIWindow :

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

By removing this line of code, the problem was resolved. Here's the rectified code:

let user = Auth.auth().currentUser
if user != nil {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let rootViewController = storyboard.instantiateViewController(identifier: "View")
    window?.rootViewController = rootViewController
    UIView.animate(withDuration: 0.5) {
        self.window?.makeKeyAndVisible()
    }
} else {
    let storyboard = UIStoryboard(name: "Auth", bundle: nil)
    let rootViewController = storyboard.instantiateViewController(identifier: "Welcome")
    window?.rootViewController = rootViewController
    UIView.animate(withDuration: 0.5) {
        self.window?.makeKeyAndVisible()
    }
}

I hope this helps anyone else facing this issue!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM