Introduction

Starting with iOS 13, Apple introduced the Scene lifecycle, moving window management from AppDelegate to SceneDelegate. If the Info.plist scene configuration does not correctly specify the delegate class name, or if the app delegate does not implement the scene lifecycle methods, the SceneDelegate never receives callbacks and the app shows a blank screen.

Symptoms

  • App launches to a black/blank screen
  • SceneDelegate.scene(_:willConnectTo:options:) is never called
  • window property is nil in SceneDelegate
  • Works on iOS 12 but shows blank screen on iOS 13+
  • application(_:configurationForConnecting:options:) not called

Example console output: `` Failed to find SceneDelegate for UIScene: <UIScene: 0x600001234567> No main window found in scene delegate

Common Causes

  • Info.plist UISceneDelegateClassName does not match the actual class name
  • Missing UIApplicationSceneManifest in Info.plist
  • App delegate does not implement application(_:configurationForConnecting:)
  • Scene configuration specifies wrong storyboard name
  • Module name not included in class name for Swift packages

Step-by-Step Fix

  1. 1.Configure Info.plist correctly:
  2. 2.```xml
  3. 3.<!-- Info.plist -->
  4. 4.<key>UIApplicationSceneManifest</key>
  5. 5.<dict>
  6. 6.<key>UIApplicationSupportsMultipleScenes</key>
  7. 7.<false/>
  8. 8.<key>UISceneConfigurations</key>
  9. 9.<dict>
  10. 10.<key>UIWindowSceneSessionRoleApplication</key>
  11. 11.<array>
  12. 12.<dict>
  13. 13.<key>UISceneConfigurationName</key>
  14. 14.<string>Default Configuration</string>
  15. 15.<key>UISceneDelegateClassName</key>
  16. 16.<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
  17. 17.<key>UISceneStoryboardFile</key>
  18. 18.<string>Main</string>
  19. 19.</dict>
  20. 20.</array>
  21. 21.</dict>
  22. 22.</dict>
  23. 23.`
  24. 24.Implement required AppDelegate scene methods:
  25. 25.```swift
  26. 26.@main
  27. 27.class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { return UISceneConfiguration( name: "Default Configuration", sessionRole: connectingSceneSession.role ) }

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { // Clean up discarded scenes } } ```

  1. 1.Implement SceneDelegate correctly:
  2. 2.```swift
  3. 3.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 }

window = UIWindow(windowScene: windowScene) window?.rootViewController = ViewController() window?.makeKeyAndVisible() }

func sceneDidBecomeActive(_ scene: UIScene) { // Called when scene moves to foreground }

func sceneWillResignActive(_ scene: UIScene) { // Called when scene moves to background } } ```

  1. 1.Opt out of scenes if you do not need them:
  2. 2.```xml
  3. 3.<!-- Remove UISceneConfiguration from Info.plist and add: -->
  4. 4.<key>UIApplicationSceneManifest</key>
  5. 5.<dict>
  6. 6.<key>UIApplicationSupportsMultipleScenes</key>
  7. 7.<false/>
  8. 8.</dict>
  9. 9.`

```swift // AppDelegate manages window directly (pre-iOS 13 style) @main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = ViewController() window?.makeKeyAndVisible() return true } } ```

Prevention

  • Verify Info.plist scene configuration matches your SceneDelegate class name
  • Use $(PRODUCT_MODULE_NAME) for the class name to handle target naming
  • Test on both iOS 13+ and earlier versions if supporting older iOS
  • Add assertions in AppDelegate to verify scene configuration at launch
  • Document the scene lifecycle in your app architecture guide
  • Consider using the @UIApplicationDelegateAdaptor pattern for SwiftUI apps