Persistence: @AppStorage & SwiftData
@AppStorage for simple settings
For small preferences (dark mode, the chosen language, a flag), @AppStorage reads and writes UserDefaults and updates the UI automatically — it’s like @State that persists across launches.
struct SettingsView: View {
@AppStorage("darkMode") private var darkMode = false
var body: some View {
Toggle("Dark mode", isOn: $darkMode) // saved automatically
}
}
Whenever the toggle changes, the value is persisted; the next launch reads it back. No manual save/load code.
SwiftData for real, structured data
For collections of objects that must persist (notes, tasks, a cached list), Apple’s SwiftData (iOS 17+) is the modern solution. You mark a class with @Model and SwiftData stores it in a local database — no SQL, very little boilerplate.
import SwiftData
@Model
class Task {
var title: String
var isDone: Bool
init(title: String, isDone: Bool = false) {
self.title = title
self.isDone = isDone
}
}
Setting up the container
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
.modelContainer(for: Task.self) // enable SwiftData
}
}
Querying and modifying data
struct TaskListView: View {
@Query(sort: \Task.title) private var tasks: [Task]
@Environment(\.modelContext) private var context
var body: some View {
List(tasks) { task in
Text(task.title)
}
.toolbar {
Button("Add") {
context.insert(Task(title: "New task")) // auto-saved
}
}
}
}
@Query automatically fetches and keeps the list in sync — insert or delete a task and the UI updates instantly, with no manual reload.
Choosing the right tool
- A few flags/settings →
@AppStorage. - Structured, growing data you query → SwiftData (or Core Data on older iOS).
- Secrets (tokens, passwords) → the Keychain (never UserDefaults).
Common mistakes
- Storing large or sensitive data in
@AppStorage/UserDefaults. - Forgetting
.modelContainersetup, so SwiftData queries fail. - Manually reloading lists instead of letting
@Querystay in sync.
Summary: Use@AppStoragefor simple persisted settings and SwiftData (@Model+@Query+modelContainer) for real structured data that stays in sync with your UI automatically.