SwiftUI
iOS14
AppDelegate
app lifecycle
iOS development

SwiftUI app life cycle iOS14 where to put AppDelegate code?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In the SwiftUI app lifecycle introduced for iOS 14, most startup code moves into the App type, not into a traditional AppDelegate. But if you still need delegate-based integration for push notifications, SDK setup, or old UIKit lifecycle hooks, SwiftUI lets you attach an AppDelegate explicitly.

Put Simple Startup Code in the App Type

For app-wide object creation and scene setup, the @main app struct is the new default home.

swift
1import SwiftUI
2
3@main
4struct DemoApp: App {
5    @StateObject private var session = SessionStore()
6
7    var body: some Scene {
8        WindowGroup {
9            ContentView()
10                .environmentObject(session)
11        }
12    }
13}

This is the right place for:

  • dependency injection
  • root environment objects
  • scene configuration
  • lightweight startup decisions

If the code is not specifically tied to UIApplicationDelegate, it usually belongs here instead of in a recreated old delegate pattern.

Use @UIApplicationDelegateAdaptor When You Need an App Delegate

Some frameworks still expect UIApplicationDelegate callbacks. SwiftUI supports that through @UIApplicationDelegateAdaptor.

swift
1import SwiftUI
2import UIKit
3
4final class AppDelegate: NSObject, UIApplicationDelegate {
5    func application(
6        _ application: UIApplication,
7        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
8    ) -> Bool {
9        print("App finished launching")
10        return true
11    }
12}
13
14@main
15struct DemoApp: App {
16    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
17
18    var body: some Scene {
19        WindowGroup {
20            ContentView()
21        }
22    }
23}

This is the standard answer when you still need delegate methods in a SwiftUI lifecycle app.

Use scenePhase for Foreground and Background State

Developers sometimes move every old lifecycle method into the delegate even when SwiftUI already gives a better hook. For foreground and background transitions, scenePhase is often the more natural SwiftUI solution.

swift
1import SwiftUI
2
3@main
4struct DemoApp: App {
5    @Environment(\.scenePhase) private var scenePhase
6
7    var body: some Scene {
8        WindowGroup {
9            ContentView()
10        }
11        .onChange(of: scenePhase) { newPhase in
12            switch newPhase {
13            case .active:
14                print("App is active")
15            case .inactive:
16                print("App is inactive")
17            case .background:
18                print("App moved to background")
19            @unknown default:
20                break
21            }
22        }
23    }
24}

This is better than forcing background and foreground logic into AppDelegate just because older UIKit apps did it that way.

How to Decide Where Code Belongs

A practical rule is:

  • use the App struct for app composition and SwiftUI-owned state
  • use scenePhase for scene lifecycle observation
  • use AppDelegate only for APIs that still require delegate callbacks

Examples of delegate-worthy code include:

  • push notification registration callbacks
  • app launch integration with certain SDKs
  • URL handling patterns that still depend on delegate methods

The question is not "Where do I put all old AppDelegate code?" The better question is "Which parts still need delegate semantics?"

What Usually Does Not Need AppDelegate Anymore

A lot of older UIKit setup code can disappear or move into more focused SwiftUI structures. View hierarchy setup belongs in the Scene body, shared model construction can live in @StateObject or dependency containers, and scene transitions can often be handled with scenePhase.

That is why many SwiftUI apps still define an AppDelegate, but keep it very small. The delegate should be the exception layer for UIKit integration, not the default home for every startup concern.

Common Pitfalls

  • Moving all legacy startup code into AppDelegate even when SwiftUI offers a better native hook.
  • Forgetting @UIApplicationDelegateAdaptor and expecting a manually defined delegate class to run by itself.
  • Using AppDelegate for scene lifecycle tracking that belongs in scenePhase.
  • Recreating a full UIKit lifecycle structure when the app is otherwise SwiftUI-first.
  • Mixing SwiftUI state management and UIKit delegate logic without clear ownership boundaries.

Summary

  • In iOS 14 SwiftUI apps, the App type is the default home for startup and composition code.
  • Use @UIApplicationDelegateAdaptor only when an actual UIApplicationDelegate callback is still needed.
  • Use scenePhase for active, inactive, and background transitions.
  • Keep UIKit delegate code narrow and intentional.
  • Porting old lifecycle code is usually a refactoring exercise, not a direct copy-paste into a new app structure.

Course illustration
Course illustration

All Rights Reserved.