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 @AppStorage and @SceneStorage do
  • 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 = defaultValue

Example: 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 = defaultValue

Example: 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., BoolStringInt).

๐Ÿ›️ 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

Popular posts from this blog

Using Core ML with SwiftUI: Build an AI-Powered App

CI/CD for iOS Projects with Xcode: A Complete Guide

Dependency Injection in iOS with SwiftUI