How Set Rootviewcontroller in Scene Delegate iOS 13

Set rootViewController iOS 13

This is because AppDelegate doesn't have window property anymore.
Now you must use SceneDelegate's scene(_:willConnectTo:options:) method to change root view controller.
Like shown in this example:

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let scene = (scene as? UIWindowScene) else { return }

// Instantiate UIWindow with scene
let window = UIWindow(windowScene: scene)
// Assign window to SceneDelegate window property
self.window = window
// Set initial view controller from Main storyboard as root view controller of UIWindow
self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
// Present window to screen
self.window?.makeKeyAndVisible()
}

when need to switch the rootViewController

Hi all i have one idea for set a RootViewController in SceneDelegate. First we need to create the method setViewController and variable currentScene in SceneDelegate class kindly feel free to refer the code below.
Two different viewcontroller as per your example HomeViewController, LoginViewController

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?
var currentScene: UIScene?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
currentScene = scene
if UserDefaults.standard.bool(forKey: "isLoggedIn") == true{
self.setRootViewController(LoginViewController())
}else{
self.setRootViewController(HomeViewController())
}
}

func setRootViewController(_ viewController: UIViewController){

guard let scene = (currentScene as? UIWindowScene) else { return }

window = UIWindow(frame: scene.coordinateSpace.bounds)
window?.windowScene = scene
window?.rootViewController = viewController
window?.makeKeyAndVisible()

}

}

class ButtonViewController: UIViewController {

lazy var button: UIButton! = {

let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = .darkGray
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
button.tag = 1
button.setTitle("Tap", for: .normal)
return button

}()


override func loadView() {
super.loadView()
self.view.backgroundColor = .white

setConstraint()
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

}

func setConstraint(){

self.view.addSubview(self.button)

NSLayoutConstraint.activate([

self.button.heightAnchor.constraint(equalToConstant: 60),
self.button.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width * 0.66),
self.button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
self.button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),

])

}

@objc func buttonAction(){ }

}

class HomeViewController: ButtonViewController{

override func loadView() {
super.loadView()
self.view.backgroundColor = .red
self.button.setTitle(String(describing: HomeViewController.self), for: .normal)
}

override func buttonAction() {
let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as! SceneDelegate
sceneDelegate.setRootViewController(LoginViewController())
}

}


class LoginViewController: ButtonViewController{

override func loadView() {
super.loadView()
self.view.backgroundColor = .green
self.button.setTitle(String(describing: LoginViewController.self), for: .normal)
}

override func buttonAction() {
let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as! SceneDelegate
sceneDelegate.setRootViewController(HomeViewController())
}

}

If click the button view controller can be change as rootViewController.
Output:

Sample Image

Update root view controller after user login + iOS 13 and later

This is how I managed navigation for both the older version and the new version. So when the user has the latest iOS we need to setup root from sceneDelegate and for older version we need to setup root from appDelegate

AppDelegate.swift

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 13, *) {

} else {
setupRoot()
}
return true
}

// MARK: UISceneSession Lifecycle
@available(iOS 13.0, *)
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

@available(iOS 13.0, *)
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {

}

func setupRoot() {
//Setup Your Root Here
//window?.rootViewController = objNavigationVC
//window?.makeKeyAndVisible()
}
}

SceneDelegate.swift

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window = window
appDelegate.setupRoot()
}
}

IOS | Unable to change root view controller in app delegate

If you are targeting only iOS 13+, the only change you should need to make is to add one line:

    window?.rootViewController = initialViewController

// add this line
self.window = window

window?.makeKeyAndVisible()

If you want to support earlier iOS versions, here is a complete SceneDelegate / AppDelegate implementation:

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>) {
}

}

set initial viewcontroller in appdelegate - swift

Xcode11 and SceneDelegate note:

Starting from Xcode11, because of SceneDelegates, it's likely that you shouldn't do it inside AppDelegate. Instead do it from SceneDelegate. For more on that see this other answer



Old answer:

I used this thread to help me convert the objective C to swift, and its working perfectly.

Instantiate and Present a viewController in Swift

Swift 2 code:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)

let storyboard = UIStoryboard(name: "Main", bundle: nil)

let initialViewController = storyboard.instantiateViewControllerWithIdentifier("LoginSignupVC")

self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()

return true
}

Swift 3 code:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)

let storyboard = UIStoryboard(name: "Main", bundle: nil)

let initialViewController = storyboard.instantiateViewController(withIdentifier: "LoginSignupVC")

self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()

return true
}


Related Topics



Leave a reply



Submit