Sample CodevisionOSReviewed 2026-07-21View on Apple Developer

Handling the window life cycle with multiple scenes

At a glance

Item Summary
Purpose Track scene state across different window types.
App architecture SampleApp composes Window + WindowGroup + volumetric window around ContentView; AppModel owns interaction while RealityView manages the entity graph.
Main patterns SwiftUI scene composition, SwiftUI–RealityKit bridge, Observable state owner
Project style Code-rich sample with 13 scanned Swift file(s) and 687 Swift line(s); resources and generated assets are excluded from those counts.

Project structure

Source bundle/
├── SampleApp/SampleApp.swift  # SceneID, SampleApp
├── SampleApp/AppModel.swift  # AppModel, WindowState
├── SampleApp/ScenePhaseMonitor.swift  # SceneStateWindowViewModifier, SceneStateWindowGroupViewModifier
├── SampleApp/SphereModel.swift  # SphereModel, ColorOption
├── SampleApp/ContentView.swift  # ContentView
├── SampleApp/ControlsView.swift  # ControlsView
├── SampleApp/SphereVolume.swift  # SphereVolume
├── SampleApp/WindowStateButton.swift  # WindowStateButton, OpenButton, CloseButton
└── Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json  # authored RealityKit content

Structure observations

  • The runtime boundary is Window + WindowGroup + volumetric window; the pruned tree lists only files that explain lifecycle, state, or framework integration.
  • App code is split into role-named views, models, managers, providers, components, or systems.
  • Authored .reality or Reality Composer Pro content is a real implementation boundary; Swift loads or drives it rather than reproducing its entity graph.

Overall architecture

Reference code

SampleApp/SampleApp.swift:17 — the app or executable entry declares the outer scene lifecycle.

struct SampleApp: App {
    // ...
}

The diagram is a responsibility flow, not a claim that every adjacent node directly calls the next. It keeps scene ownership, shared state, RealityKit content, and framework-provider work at separate levels.

Ownership and state

Ownership evidence

SampleApp/SampleApp.swift:18 — representative stored state or the nearest verified lifecycle anchor.

    @State private var appModel = AppModel()
Owner Object or state Relationship Mutation authority
SampleApp AppModel as appModel creates and retains Only the declaring scope writes
WindowState WindowState as sphereLauncherWindowState stores and coordinates The owning type coordinates writes
WindowStateButton SphereModel as sphere stores and coordinates The owning type coordinates writes
OpenButton SphereModel as sphere stores and coordinates The owning type coordinates writes

Ownership here is deliberately narrow: @Environment and weak references are shared links, initialized @State or stored services are lifecycle ownership, and a RealityView content closure owns additions to its entity graph without making the SwiftUI view a reference-type owner.

Class and protocol design

Type Responsibility Depends on or conforms to
SampleApp (SampleApp/SampleApp.swift:17) Declares app scenes and top-level dependency lifetime. App
ContentView (SampleApp/ContentView.swift:10) Presents UI and forwards gestures or lifecycle events. View
AppModel (SampleApp/AppModel.swift:11) Owns observable feature state and domain transitions. Concrete framework collaborators
SphereModel (SampleApp/SphereModel.swift:10) Owns observable feature state and domain transitions. Codable, Hashable, Identifiable
ControlsView (SampleApp/ControlsView.swift:10) Presents UI and forwards gestures or lifecycle events. View

The source defines no local substitution protocol in the reviewed boundary. Its protocol use is framework-facing (App, View, RealityKit/ARKit protocols, or platform adapters), so this document does not label the whole app protocol-oriented.

Access control

Symbol Access Verified effect Likely rationale
@Environment(AppModel.self) private var appModel (SampleApp/ControlsView.swift:11) private Use is restricted to the declaration and same-file extensions permitted by Swift. Inference: Hide implementation details and lifecycle-sensitive state.
public let realityKitContentBundle = Bundle.module (Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift:11) public The declaration is available to importing modules, subject to its containing type’s visibility. Inference: Export the type across the package-module boundary.

No reviewed declaration uses fileprivate, private(set), open; unmodified Swift declarations are internal.

Reference code

SampleApp/ControlsView.swift:11 — representative visibility boundary.

    @Environment(AppModel.self) private var appModel
    @Environment(\.openWindow) private var openWindow
    @Environment(\.dismissWindow) private var dismissWindow

    @SceneStorage("enlarge") private var enlarge: Bool = false

Logic ownership and placement

Logic Owning type or file Placement rationale
Scene declaration and dependency lifetime SampleApp The App/entry boundary determines window, volume, and immersive-space lifetime.
Presentation, attachments, and gestures ContentView SwiftUI view code forwards user intent and RealityView lifecycle events.
Shared feature state and commands AppModel A role-named owner prevents sibling views from duplicating transitions.

Design patterns

Pattern Source evidence Purpose or tradeoff
SwiftUI scene composition SampleApp/SampleApp.swift:17 Keeps windows, volumes, and immersive-space lifecycle visible at the app boundary.
SwiftUI–RealityKit bridge SampleApp/SphereVolume.swift:20 Builds and updates a RealityKit entity graph from SwiftUI lifecycle closures.
Observable state owner SampleApp/AppModel.swift:11 Shares feature state across multiple views without moving framework resources into view values.

Naming conventions

  • Role suffixes are evidence, not decoration: App: SampleApp; Model: AppModel, SphereModel; View: ContentView, ControlsView.
  • Protocols: no app-defined protocol in the reviewed source.
  • Commands use verb-led methods: updateWindowState, unregisterWindow, windowState, monitorScenePhase, body.
  • Files generally match their primary type; Views, Models, Managers, Providers, Components, Systems, and Packages folders describe architectural roles where present.

Architecture takeaways

  • Treat SampleApp as the owner of scene declarations, not as the owner of every RealityKit entity created later.
  • Keep view-local interaction in SwiftUI, but move provider sessions, playback resources, shared game state, or transport state into a stable owner when their lifetime exceeds one render pass.

Source map

Source file Relevant symbols
SampleApp/SampleApp.swift:10 SceneID, SampleApp
SampleApp/AppModel.swift:11 AppModel, WindowState
SampleApp/ScenePhaseMonitor.swift:57 SceneStateWindowViewModifier, SceneStateWindowGroupViewModifier
SampleApp/SphereModel.swift:10 SphereModel, ColorOption
SampleApp/ContentView.swift:10 ContentView
SampleApp/ControlsView.swift:10 ControlsView
SampleApp/SphereVolume.swift:12 SphereVolume
SampleApp/WindowStateButton.swift:10 WindowStateButton, OpenButton, CloseButton