100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Swift

App and Scene Structure

Understand how the App and Scene protocols define a SwiftUI application's entry point, window management, and lifecycle across platforms.

Architecture PatternsBeginner8 min readJul 8, 2026
Analogies

App and Scene Structure

Every SwiftUI application has a single type conforming to the App protocol, marked with @main, which serves as its entry point in place of a traditional AppDelegate/UIApplicationMain setup. The App protocol requires a single computed property, body, whose type conforms to Scene. A scene describes a piece of the app's user interface lifecycle — most commonly a WindowGroup, which manages one or more windows displaying the same root view. This declarative structure replaces the imperative window and view-controller bootstrapping that UIKit apps historically required in AppDelegate and SceneDelegate.

🏏

Cricket analogy: A Test match series has one designated home board (@main) that sets the whole tour's fixture list (Scene), replacing the old days when individual county clubs arranged matches ad hoc.

swift
@main
struct MyStoreApp: App {
    @State private var cartManager = CartManager()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(cartManager)
        }

        #if os(macOS)
        Settings {
            SettingsView()
        }
        #endif
    }
}

WindowGroup and Multiple Windows

WindowGroup is the workhorse scene type: on iOS it typically produces one window per app instance (with multitasking, this can be more on iPadOS), while on macOS it allows the user to open multiple independent windows of the same scene, each with its own navigation state. Because WindowGroup's content closure is re-evaluated for each new window, any state you want to be per-window — versus shared app-wide state living in an @State property on the App type — should live inside the root view itself.

🏏

Cricket analogy: Each IPL franchise runs its own independent squad and season campaign (a separate WindowGroup instance) even though all franchises share the same league rulebook (@State on the App type), so Mumbai Indians' playing XI stays separate per match from Chennai Super Kings'.

Other Scene Types

Beyond WindowGroup, SwiftUI offers specialized scenes: DocumentGroup for document-based apps that need open/save/new-document semantics tied to a file type; Settings for a macOS-only preferences window accessible from the app menu; and MenuBarExtra for macOS menu bar utility apps. On watchOS, WKNotificationScene and related scene types integrate with the watch's app model. Each scene type encapsulates platform-specific lifecycle and chrome so the SwiftUI code stays declarative rather than manually managing UIWindow or NSWindow instances.

🏏

Cricket analogy: Just as a stadium has distinct zones for the pitch, the scoreboard control room, and the members' pavilion, each built for a specific purpose, SwiftUI offers DocumentGroup for file-based apps, Settings for macOS preferences, and MenuBarExtra for menu-bar utilities, each purpose-built rather than one generic window.

Think of App as the declaration of 'what kinds of windows this application can open' rather than 'what this application does when it launches' — the imperative launch sequence (splash screens, initial routing, dependency setup) happens inside the root view's .task or init, not in the App type's body, which is purely declarative.

Scene Phase and Lifecycle

SwiftUI exposes the app's current lifecycle state through the \.scenePhase environment value, which is one of .active, .inactive, or .background. Reading it with @Environment(\.scenePhase) in a view or in the App type itself lets you react to transitions — for example, saving data when the app moves to .background, or pausing a timer when it becomes .inactive (such as when a system alert or the app switcher appears).

🏏

Cricket analogy: A match transitions through states just like scenePhase: play in progress (.active), a brief drinks break or review pause (.inactive), and stumps drawn for the day (.background) — smart teams save their game plan notes exactly when stumps are called.

swift
@main
struct MyStoreApp: App {
    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { _, newPhase in
            if newPhase == .background {
                PersistenceController.shared.save()
            }
        }
    }
}

.background on iOS does not guarantee the process stays alive — iOS can suspend or terminate a backgrounded app at any time to reclaim memory. Any critical save work triggered on the .background transition must complete quickly and synchronously (or via a background task) rather than assuming a long-running window to finish asynchronous work.

  • A SwiftUI app has exactly one @main type conforming to App, whose body returns one or more Scene values.
  • WindowGroup is the primary scene type, producing per-window instances of a root view (single window on iOS, multiple on macOS).
  • DocumentGroup, Settings, and MenuBarExtra are specialized scenes for document apps, macOS preferences, and menu bar utilities respectively.
  • The App type is purely declarative — imperative setup belongs in the root view's init or .task, not the app's body.
  • \.scenePhase reports .active, .inactive, or .background, letting code react to lifecycle transitions.
  • Work triggered on a .background transition must be fast or use a background task, since iOS can suspend the process at any time.

Practice what you learned

Was this page helpful?

Topics covered

#Swift#IOSWithSwiftUIStudyNotes#MobileDevelopment#AppAndSceneStructure#App#Scene#Structure#WindowGroup#StudyNotes#SkillVeris