Scene Lifecycle
What Is a Scene?
A Scene represents a single instance of your app's UI, typically a window. iOS 13+ uses the scene architecture to support multiple windows on iPad and handle system-managed scene lifecycle.
Each scene has its own UISceneDelegate (or UIWindowSceneDelegate) that responds to lifecycle events specific to that window.
Scene Lifecycle Methods
The UIScene protocol provides these key methods:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Scene is about to connect
// Set up the window and root view controller
guard let windowScene = scene as? UIWindowScene else { return }
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: ContentView())
self.window = window
window.makeKeyAndVisible()
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Scene became active (foreground)
}
func sceneWillResignActive(_ scene: UIScene) {
// Scene will become inactive
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Scene entered background
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Scene will enter foreground from background
}
}
SwiftUI Equivalents
In SwiftUI, you handle scene lifecycle through the App struct and environment:
@main
struct MyApp: App {
@Environment(\.scenePhase) var scenePhase
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase) { _, phase in
switch phase {
case .active: handleActive()
case .inactive: handleInactive()
case .background: handleBackground()
@unknown default: break
}
}
}
func handleActive() { /* scene became active */ }
func handleInactive() { /* scene will resign active */ }
func handleBackground() { /* scene entered background */ }
}
Scene Session
Each scene has a UISceneSession that holds persistent data for that scene. The system uses this to restore scenes after termination:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) {
// session.stateRestorationActivity contains saved state
if let activity = session.stateRestorationActivity {
// Restore from activity
}
}
In SwiftUI, WindowGroup handles state restoration automatically.
Multi-Window on iPad
Enabling Multi-Window
iPad apps support multiple windows by default when using WindowGroup. To explicitly control this:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup("Main") {
ContentView()
}
}
}
To open a new window, the system provides the newWindowScene action:
struct ContentView: View {
@Environment(\.openWindow) var openWindow
var body: some View {
Button("Open Settings Window") {
openWindow(id: "settings")
}
}
}
Define the window group in your App struct:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup("Main") {
ContentView()
}
WindowGroup(id: "settings") {
SettingsView()
}
}
}
Scene Phases on iPad
Each scene has its own phase. One scene can be active while another is in the background:
struct ContentView: View {
@Environment(\.scenePhase) var scenePhase
var body: some View {
Text("This scene is \(scenePhase == .active ? "active" : "not active")")
}
}
Handling Scene Destruction
The system can destroy scenes to free resources. The scene phase transitions to .background before destruction:
.onChange(of: scenePhase) { _, phase in
if phase == .background {
// Save scene-specific state before potential destruction
saveSceneState()
}
}
Scene-Level Configuration
Each scene can have different configurations:
var body: some Scene {
WindowGroup("Document") {
DocumentEditor()
}
.defaultSize(width: 800, height: 600)
.windowResizability(.contentSize)
WindowGroup("Inspector") {
InspectorView()
}
.defaultSize(width: 300, height: 400)
}
Universal Apps
For apps that run on both iPhone and iPad:
#if os(iOS)
// iOS-specific scene configuration
#elseif os(macOS)
// macOS-specific scene configuration
#endif
Multi-window is primarily an iPad feature. iPhone apps have a single scene managed by the system.
Scene Phases
Scene Phase Values
SwiftUI defines three scene phase values:
- .active - The scene is in the foreground and receiving user interaction
- .inactive - The scene is in the foreground but not receiving events (transitional state)
- .background - The scene is in the background, not visible to the user
Responding to Phase Changes
@main
struct MyApp: App {
@Environment(\.scenePhase) var scenePhase
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase) { _, newPhase in
switch newPhase {
case .active:
resumeTimers()
refreshContent()
case .inactive:
pauseTimers()
saveDraft()
case .background:
saveAllState()
releaseHeavyResources()
@unknown default:
break
}
}
}
}
Per-Scene Phase Observation
Each WindowGroup has its own scene phase. Multiple windows can be in different phases simultaneously:
struct MyScene: Scene {
var body: some Scene {
WindowGroup("Window 1") {
ContentView()
}
.onChange(of: scenePhase) { _, phase in
// Only affects Window 1
}
}
}
Practical Patterns
Auto-save on background:
.onChange(of: scenePhase) { _, phase in
if phase == .background {
modelContext.save()
}
}
Resume animations when active:
@State private var isAnimating = false
.onChange(of: scenePhase) { _, phase in
if phase == .active {
withAnimation { isAnimating = true }
} else {
isAnimating = false
}
}
Connect to services when active:
.onChange(of: scenePhase) { _, phase in
if phase == .active {
connectWebSocket()
} else if phase == .background {
disconnectWebSocket()
}
}
Inactive State
The inactive state is brief and transitional. Common triggers include:
- Incoming phone call
- Siri activation
- App switcher gesture
- Notification banner overlay
Do not perform heavy work in the inactive state. Use it to pause ongoing operations that should not continue in the background.
Quiz
1. What is a UISceneSession?
2. How do you enable multi-window on iPad in SwiftUI?
3. What are the three scene phase values in SwiftUI?
4. When does the inactive scene phase occur?
5. How does SwiftUI handle state restoration for WindowGroup?
Flashcards
Question
What does UISceneSession hold?
Click to reveal answer
Answer
Persistent data for a scene, used for state restoration after termination.
Question
How do you open a new window on iPad?
Click to reveal answer
Answer
Use @Environment(\.openWindow) and call openWindow(id:) with a defined WindowGroup id.
Question
What is the .inactive scene phase?
Click to reveal answer
Answer
A brief transitional state when the scene is in the foreground but not receiving events.
Question
How do multiple WindowGroups behave on iPad?
Click to reveal answer
Answer
Each WindowGroup creates a separate window that can be in a different scene phase.
Question
What triggers the .background scene phase?
Click to reveal answer
Answer
When the scene is no longer visible, such as when the user switches to another app.
Revision Notes
Key Takeaways
- 1. A Scene represents a single window with independent lifecycle
- 2. UISceneSession stores persistent scene data for restoration
- 3. Three scene phases: active, inactive, background
- 4. Multiple WindowGroups enable multi-window on iPad
- 5. WindowGroup handles state restoration automatically
Interview Tips
- • Explain the difference between scene lifecycle and app lifecycle
- • Know how to enable and manage multi-window on iPad
- • Understand when each scene phase occurs and how to respond
- • Be ready to discuss state restoration with WindowGroup
Cheat Sheet
Scene = one window instance with its own lifecycle.
UISceneSession holds persistent data for restoration.
Three phases: active, inactive, background.
Multi-window: multiple WindowGroups in App struct.
.openWindow(id:) opens new windows on iPad.