J'ai le code suivant dans mon AppDelegate.Swift pour configurer le contrôleur de vue racine pour une application iOS. Mais ça ne marche pas. Il suit la structure cible (définie sous l'onglet Général) et ignore ce code.
(Xcode 11, Swift 5.1, iOS 13)
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
guard let rootVC = UIViewController() else {
print("Root VC not found")
return true
}
let rootNC = UINavigationController(rootViewController: rootVC)
window?.rootViewController = rootNC
window?.makeKeyAndVisible()
return true
}
}
Impossible de comprendre où est le problème.
J'ai aussi essayé de suivre les références mais pas de chance:
J'ai essayé de suivre deux options et les deux fonctionnaient pour moi. Avec iOS-13 (Xcode 11), un nouveau fichier SceneDelegate.Swift avec le concept UIWindowScene est activé par défaut.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: windowScene)
//self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
guard let rootVC = storyboard?.instantiateViewController(identifier: "ViewControllerIdentifierName") as? ViewController else {
print("ViewController not found")
return
}
let rootNC = UINavigationController(rootViewController: rootVC)
self.window?.rootViewController = rootNC
self.window?.makeKeyAndVisible()
}
}
Alterner:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let windowScene = UIWindowScene(session: session, connectionOptions: connectionOptions)
self.window = UIWindow(windowScene: windowScene)
//self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
guard let rootVC = storyboard?.instantiateViewController(identifier: "ViewControllerIdentifierName") as? ViewController else {
print("ViewController not found")
return
}
let rootNC = UINavigationController(rootViewController: rootVC)
self.window?.rootViewController = rootNC
self.window?.makeKeyAndVisible()
}
}
Je ne sais pas, pourquoi et comment cela fonctionne mais cela a résolu mon problème.
Documents de référence qui m'ont aidé:
J'ai essayé l'approche suivante et cela fonctionne pour moi dans iOS 13 et j'ai également testé sur iOS 12.4.2 de Xcode 11.
func resetRoot() {
guard let rootVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as? ViewController else {
return
}
let navigationController = UINavigationController(rootViewController: rootVC)
UIApplication.shared.windows.first?.rootViewController = navigationController
UIApplication.shared.windows.first?.makeKeyAndVisible()
}
Premier cas
Si la majeure partie de votre projet est intégrée dans le storyboard et avant que Xcode 11 ne soit utilisé pour le développement et que vous n'utilisez pas SwiftUI, vous souhaitez utiliser vos anciennes classes associées à AppDelegate.
Supprimez complètement ScenceDelegate du projet.
Ensuite, vous pourrez utiliser votre ancien code.
Deuxième cas
Si vous souhaitez utiliser à la fois Appdelegte et ScenceDelegate, le code fonctionne ci-dessous.
Code de délégué d'application:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 13.0, *){
//do nothing we will have a code in SceneceDelegate for this
} else {
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let VC = mainStoryboard.instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
navigationController?.isNavigationBarHidden = true
navigationController = UINavigationController(rootViewController: VC)
navigationController?.isNavigationBarHidden = true // or not, your choice.
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window!.rootViewController = navigationController
}
return true
}
Code ScenceDelegate:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let VC = mainStoryboard.instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
navigationController?.isNavigationBarHidden = true
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window.windowScene = windowScene
window.rootViewController = VC
window.makeKeyAndVisible()
let appDelegate = UIapplication.shared.delegate as! AppDelegate
appDelegate.window = window
}
Voici ce qui fonctionne pour iOS 13.x et iOS 12.x et inférieur
Pour iOS 13, Délégué In the Scene
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(frame: windowScene.coordinateSpace.bounds)
//Make sure to do this else you won't get
//the windowScene object using UIApplication.shared.connectedScenes
self.window?.windowScene = windowScene
let storyBoard: UIStoryboard = UIStoryboard(name: storyBoardName, bundle: nil)
window?.rootViewController = storyBoard.instantiateInitialViewController()
window?.makeKeyAndVisible()
}
Dans une classe utilitaire, j'ai écrit ci-dessous la fonction pour obtenir l'objet window
et l'assigner à appdelegate.window
. Selon mes besoins, je devais définir le contrôleur de vue racine à plusieurs endroits dans différents scénarios pour lesquels j'avais besoin de l'objet fenêtre.
static func redirectToMainNavRVC(currentVC: UIViewController){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let vc = UIStoryboard(name: appDelegate.storyBoardName, bundle: nil).instantiateViewController(withIdentifier: "MainNavigationViewController") as! MainNavigationViewController
if #available(iOS 13.0, *){
if let scene = UIApplication.shared.connectedScenes.first{
guard let windowScene = (scene as? UIWindowScene) else { return }
print(">>> windowScene: \(windowScene)")
let window: UIWindow = UIWindow(frame: windowScene.coordinateSpace.bounds)
window.windowScene = windowScene //Make sure to do this
window.rootViewController = vc
window.makeKeyAndVisible()
appDelegate.window = window
}
} else {
appDelegate.window?.rootViewController = vc
appDelegate.window?.makeKeyAndVisible()
}
}
Cela a bien fonctionné pour moi. Espérons que cela fonctionne aussi pour les autres.
var window: UIWindow?
a été déplacé d'AppdDelegate.Swift vers SceneDelegate.Swift.
J'ai donc utilisé rootViewController dans la classe Scene Delegate et cela fonctionne -
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 }
if let tabBarController = window?.rootViewController as? UITabBarController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(identifier: "NavController")
vc.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 1)
tabBarController.viewControllers?.append(vc)
}
}
J'ai fait deux choses. Tout d'abord, j'ai défini un Notification
en SceneDelegate
, puis quand j'ai eu besoin de changer le RootViewController
j'ai fait un Notification Post
et cela a fonctionné. Mais c'est une solution angoissante.
Mon patron m'a recommandé de changer le Controllers
du NavigationController
, quelque chose comme ceci:
func logged() {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "MainTabViewController", bundle: nil)
let mainVC = mainStoryboard.instantiateInitialViewController()
self.navigationController?.setViewControllers([mainVC!], animated: false)
}
Je sais que ce n'est peut-être pas la meilleure solution, mais je la vois plus propre.
Je travaille maintenant sur iOS 13 et je ne voulais pas utiliser deprecated
choses.