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:
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
Swiftui List Empty State View/Modifier
How to Use Sf Rounded Font in Swiftui
How to Cache Images Using Urlsession in Swift
Can't Hook Up an Outlet Collection in Xcode 6 Using Storyboard
Why Unsaferawpointer Shows Different Result When Function Signatures Differs in Swift
Swift 3: Convert a Null-Terminated Unsafepointer<Uint8> to a String
Constant Speed Orbit Around Point with Sknode
How to Bind Different Associated Values in a Swift Enum to the Same Var
Swift 5.5: Asynchronously Iterating Line-By-Line Through a File
Swift, Auto Resize Custom Table View Cells
"Generic Parameter Could Not Be Inferred" in Swiftui Uiviewrepresentable
Swiftui Customized Text Field in Osx
Why Should Not Directly Extend Uiview or Uiviewcontroller
How to Test Whether Generic Variable Is of Type Anyobject
Invalid Update: Invalid Number of Items in Section 0
Swift - Avaudioplayer, Sound Doesn't Play Correctly
Extending Collection with a Recursive Property/Method That Depends on the Element Type