How to Use AppStorage and SceneStorage in SwiftUI for State Persistence
One of SwiftUI’s most powerful features is its ability to persist UI state across app launches and scene sessions with minimal code. Two key property wrappers that enable this are @AppStorage and @SceneStorage.
In this blog, we’ll cover:
- What
@AppStorageand@SceneStoragedo - When to use each
- Hands-on examples to implement them
๐ก What is @AppStorage?
@AppStorage is a property wrapper that connects directly to UserDefaults. It allows you to persist simple values like strings, numbers, booleans, etc., across app launches.
Syntax:
@AppStorage("key") var value: Type = defaultValueExample: Storing Dark Mode Preference
struct SettingsView: View {
@AppStorage("isDarkMode") private var isDarkMode = false
var body: some View {
Toggle("Dark Mode", isOn: $isDarkMode)
.padding()
}
}Here, the toggle state is automatically saved and restored using UserDefaults.
๐ What is @SceneStorage?
@SceneStorage persists values per scene/session, such as when your app supports multi-window mode (like on iPad or macOS). It is perfect for short-term state like scroll positions or text inputs that should restore when the scene is reopened.
Syntax:
@SceneStorage("key") var value: Type = defaultValueExample: Persisting TextField Input
struct NoteView: View {
@SceneStorage("note") private var noteText: String = ""
var body: some View {
TextEditor(text: $noteText)
.padding()
}
}The noteText will be restored when the scene is reopened.
๐ค When to Use @AppStorage vs. @SceneStorage
Understanding when to use each property wrapper can improve your app’s UX and reduce code complexity. Here’s a quick breakdown:
๐ Use @AppStorage When:
- You want to persist data across app launches.
- You’re storing user preferences, like dark mode, app language, or login status.
- You want data to be available globally across multiple views or scenes.
- You’re working with simple values (e.g.,
Bool,String,Int).
๐️ Use @SceneStorage When:
- You want to retain UI state only within a single scene session.
- You’re building apps that support multi-window environments, like on iPadOS or macOS.
- You need to preserve temporary view state, such as:
- Scroll position
- Text editor input
- Currently selected tab or view
Think of @SceneStorage as perfect for restoring the exact screen state when a user reopens a window.
๐ Bonus Tip: Custom Types with AppStorage
Want to store a custom enum or object? Make it Codable, then convert to Data or String manually:
enum Theme: String, Codable {
case light, dark
}
extension UserDefaults {
func setTheme(_ theme: Theme) {
if let data = try? JSONEncoder().encode(theme) {
set(data, forKey: "selectedTheme")
}
}
func getTheme() -> Theme {
if let data = data(forKey: "selectedTheme"),
let theme = try? JSONDecoder().decode(Theme.self, from: data) {
return theme
}
return .light
}
}๐ Wrapping Up
With just a few lines of code, @AppStorage and @SceneStorage make it effortless to preserve state and provide a better user experience.
Use @AppStorage for user preferences that should persist across launches.
Use @SceneStorage for temporary data within a scene session.

Comments
Post a Comment