iOS 13.1切换Root View Controller时App崩溃,iOS 12运行正常
I’ve run into this exact issue before—iOS 13 introduced key changes to how UIWindow and view controller lifecycles interact, which breaks the root view controller switching pattern that worked reliably in iOS 12 and earlier.
What’s Causing the Crash?
Your current implementation modifies rootViewController inside the UIView.transition animation block while temporarily disabling animations. In iOS 13+, this creates a conflict with the system’s scene lifecycle management and view controller state validation. The system expects rootViewController changes to be explicit state updates outside of animation blocks, and doing this inside the transition’s animation closure leads to an inconsistent state that triggers a crash.
Fixed Implementation
Here’s an updated version of your UIWindow extension that works reliably across iOS 12 and iOS 13+:
extension UIWindow { func switchRootViewController(_ viewController: UIViewController, animated: Bool = true, duration: TimeInterval = 0.3, options: UIView.AnimationOptions = .transitionFlipFromRight, completion: (() -> Void)? = nil) { guard animated else { rootViewController = viewController makeKeyAndVisible() completion?() return } // Add the new view controller's view to the window first viewController.view.frame = bounds addSubview(viewController.view) // Animate the transition between old and new views UIView.transition(with: self, duration: duration, options: options, animations: { self.rootViewController?.view.removeFromSuperview() }) { [weak self] _ in guard let self = self else { return } // Update rootViewController after animation completes to avoid state conflicts self.rootViewController = viewController self.makeKeyAndVisible() completion?() } } }
Key Changes:
- Avoid modifying
rootViewControllerduring animation: We first add the new view controller’s view as a subview to the window, ensuring the visual transition is handled separately from the state update. - Animate removal of the old view: The transition animation manages hiding the old root view controller’s view, keeping the visual flow smooth.
- Update
rootViewControllerpost-animation: Once the visual transition finishes, we set the new view controller as the root and clean up, ensuring the system’s state remains consistent. - Explicit
makeKeyAndVisible()call: This ensures the window is properly associated with the scene in iOS 13+, addressing scene lifecycle requirements.
Additional Notes
- If you’re using Scenes (iOS 13+), avoid relying on
UIApplication.shared.keyWindow(now deprecated) and instead access the correct window from your scene delegate. - Test edge cases like rapid root view controller switches to ensure no unexpected behavior.
内容的提问来源于stack exchange,提问作者Sandeep Kashyap

