iosNudge

Explain the iOS app lifecycle. What do AppDelegate and SceneDelegate do?

EasyAsked oftenApp lifecycleUIKitSwiftUI 2 min read

TL;DR

App states: Not running → Inactive → Active → Inactive → Background → Suspended. Since iOS 13, the work is split:

  • AppDelegate: process-level events (launch, push token registration, scene setup).
  • SceneDelegate: one scene (window) at a time. Foreground, background, URLs.

In SwiftUI, the App struct plus scenePhase replaces most of this.

The states

StateMeaning
Not runningNot launched, or killed by the system
InactiveIn the foreground but not getting events (phone call, Control Center, during transitions)
ActiveIn the foreground, the user is using it
BackgroundNot visible, still running code for a short time
SuspendedIn memory but not running code. Can be killed with no warning

Important: the system does not tell you before it kills a suspended app. Save data when you enter the background.

AppDelegate

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Set up crash reporting, logging, background task registration.
        return true
    }

    func application(_ application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        // Send the push token to your server.
    }

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

SceneDelegate

final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
               options: UIScene.ConnectionOptions) {
        guard let windowScene = scene as? UIWindowScene else { return }
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = RootViewController()
        window.makeKeyAndVisible()
        self.window = window
    }

    func sceneDidBecomeActive(_ scene: UIScene) { /* resume timers */ }
    func sceneWillResignActive(_ scene: UIScene) { /* pause game */ }
    func sceneWillEnterForeground(_ scene: UIScene) { /* refresh data */ }
    func sceneDidEnterBackground(_ scene: UIScene) { /* save state */ }
}

On iPad and Mac, one app can have many scenes (windows). Each has its own scene delegate and UI state.

SwiftUI

@main
struct NotesApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup { ContentView() }
            .onChange(of: scenePhase) { _, phase in
                switch phase {
                case .active: print("active")
                case .inactive: print("inactive")
                case .background: print("save now")
                @unknown default: break
                }
            }
    }
}

Use @UIApplicationDelegateAdaptor when you still need app delegate methods, like push token registration.

Launch flow

  1. User taps the icon. The process starts.
  2. application(_:didFinishLaunchingWithOptions:).
  3. A scene is created: scene(_:willConnectTo:options:).
  4. sceneWillEnterForeground, then sceneDidBecomeActive.

Why scenes matter now

Apple has said the UIScene life cycle will be required for apps built with the SDK after iOS 26. Old app-delegate-only apps must migrate. This is a good, current detail to mention.

Where to do what

TaskPlace
Save user datasceneDidEnterBackground / .background phase
Pause a game or videosceneWillResignActive
Refresh stale datasceneWillEnterForeground
Register background tasksdidFinishLaunching (before it returns)
Handle a URL or universal linkScene delegate or .onOpenURL

Common follow-up questions

  • Is applicationWillTerminate reliable? No. It is not called when a suspended app is killed.
  • How long can the app run in the background? A few seconds by default. Ask for more with beginBackgroundTask, or use background modes.
  • What happens to scenes when the user swipes them away? The scene is disconnected and sceneDidDisconnect is called. The session may be restored later.
  • What is state restoration? Saving UI state in NSUserActivity or @SceneStorage so the app looks the same after relaunch.