How it works
SceneStorage is a property wrapper that persists small pieces of view state per scene, automatically saving and restoring them as the system manages a scene's lifecycle. Use it for transient, scene-scoped UI state — a draft message, a selected tab, a scroll position — that should survive when a scene is backgrounded and later restored, but that is not part of your app's permanent model. Unlike AppStorage, each scene gets its own independent value keyed by the scene's identity, so two windows of the same app don't clobber each other. Reach for SceneStorage when you want the system's state-restoration machinery to remember where the user left off, without writing any save or restore code yourself.
Declare the wrapper with a string key
Attach @SceneStorage to a stored property and give it a key that uniquely names this value within the scene's storage. The wrapped value is read and written like an ordinary property, but every change is checkpointed for restoration. In the example, @SceneStorage("draftText") private var draft = "" keys the draft under "draftText".
Provide a default value of a supported type
The initial value both seeds the property the first time the scene appears and fixes the storage type. SceneStorage supports the same lightweight types as the restoration system — Bool, Int, Double, String, URL, Data, and RawRepresentable types whose raw value is Int or String. Here the default "" makes draft a stored String that starts empty.
Bind the value into a control with the projected value
Like other SwiftUI state wrappers, SceneStorage exposes a Binding through its projected value, accessed with the $ prefix. Pass that binding to any view that reads and writes the value so edits flow straight into scene storage. In the example, $draft drives the TextField, so each keystroke updates the persisted draft.
Read the wrapped value directly in the view
Reading the property without the $ gives you the current value for display or logic; the restored value is already in place by the time body runs. The example reads draft directly in Text("Saved per scene: \(draft)") to echo whatever the scene last held.
Rely on per-scene identity and automatic restoration
You never call save or load — SwiftUI persists each SceneStorage value against the enclosing scene and restores it when that scene is recreated, while keeping separate scenes' values isolated. The draft typed into one SceneStorageDemo scene comes back on relaunch of that scene and stays distinct from a draft in another window.
Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct SceneStorageDemo: View {
@SceneStorage("draftText") private var draft = ""
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Compose")
.font(.headline)
TextField("Type a note…", text: $draft)
.textFieldStyle(.roundedBorder)
Text("Saved per scene: \(draft)")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding()
}
}