iOS报错求助:试图在视图不在窗口层级的UINavigationController上呈现控制器
Hey David, let's break down this frustrating warning you're seeing. The error says you're trying to present one UINavigationController on top of another whose view isn't part of the window hierarchy—but since your LoginViewController isn't wrapped in a navigation controller, the issue is likely tied to your segue configuration or how you're handling the prepare(for:sender:) method. Here's how to troubleshoot and fix it:
1. Double-Check Your Storyboard Segue Type
First, head to your Storyboard and select the segue with identifier "GoToMainVC". In the Attributes Inspector, look at the "Kind" dropdown:
- If it's set to Show (e.g. Push), that's the problem.
LoginViewControllerisn't part of a navigation stack, so push segues won't work here. Change this to Present Modally instead. - If it's already set to Present Modally, confirm the segue's destination is either your
MainViewController(wrapped in aUINavigationControllerin the Storyboard) or directly theUINavigationControllerthat containsMainViewController.
2. Clean Up Your prepare(for:sender:) Method
The most common mistake here is accidentally adding an extra present() call inside the prepare method—remember, performSegue(withIdentifier:sender:) already handles the presentation for you. Your prepare method should only handle data passing, not triggering presentation.
Bad example (what you might be doing):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "GoToMainVC" { let navVC = segue.destination as! UINavigationController self.present(navVC, animated: true) // ❌ Duplicate presentation causes hierarchy issues } }
Good example (correct usage):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard segue.identifier == "GoToMainVC" else { return } // If your segue targets a UINavigationController, access its root/main view controller if let navVC = segue.destination as? UINavigationController, let mainVC = navVC.topViewController as? MainViewController { // Pass data to MainViewController here, e.g.: // mainVC.currentUser = loggedInUser } // If your segue targets MainViewController directly (less common if you need a nav stack): // let mainVC = segue.destination as! MainViewController // mainVC.currentUser = loggedInUser }
3. Ensure performSegue Runs on the Main Thread
If your login logic uses async operations (like network requests), make sure you call performSegue from the main thread. UI operations must always run on the main thread, and skipping this can cause weird view hierarchy glitches:
// Example: After successful login network call DispatchQueue.main.async { self.performSegue(withIdentifier: "GoToMainVC", sender: nil) }
4. Alternative: Replace the Root View Controller (If Segues Keep Causing Issues)
If you're still hitting problems, an alternative approach is to replace the app's root view controller directly instead of using a segue. This avoids any hierarchy confusion entirely:
// After successful login self.dismiss(animated: true) { // Load your MainViewController and wrap it in a nav controller let storyboard = UIStoryboard(name: "Main", bundle: nil) let mainVC = storyboard.instantiateViewController(withIdentifier: "MainVC") as! MainViewController let mainNavVC = UINavigationController(rootViewController: mainVC) // Set as root view controller (iOS 13+ compatible) if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = windowScene.windows.first { window.rootViewController = mainNavVC window.makeKeyAndVisible() } }
This method ensures you're completely replacing the login flow with your main app flow, eliminating any chance of view hierarchy conflicts.
内容的提问来源于stack exchange,提问作者David

