Alle Beiträge

SwiftUI Daten speichern – @AppStorage, UserDefaults und SwiftData

SwiftUI Daten speichern – @AppStorage, UserDefaults und SwiftData

Warum Daten persistieren?

Deine App startet, der User stellt Dark Mode ein, legt Favoriten an, gibt seinen Namen ein — und nach dem nächsten App-Neustart ist alles weg. Ohne Persistenz fühlt sich eine App kaputt an. Die gute Nachricht: SwiftUI macht es einfach, Daten dauerhaft zu speichern.

Es gibt drei Wege, je nach Komplexität:

AnsatzWann verwenden
<code>@AppStorage</code>Einfache Einstellungen (Bool, String, Int)
<code>UserDefaults</code> direktWenn <code>@AppStorage</code> nicht reicht (Arrays, Dictionaries)
<code>SwiftData</code>Komplexe Datenmodelle, Beziehungen, Suche

@AppStorage – Einstellungen in einer Zeile

@AppStorage ist ein Property Wrapper, der direkt an UserDefaults gebunden ist. Er liest und schreibt automatisch — du musst dich um nichts kümmern:

struct SettingsView: View {
    @AppStorage("isDarkMode") private var isDarkMode = false
    @AppStorage("username") private var username = ""
    @AppStorage("fontSize") private var fontSize = 16.0

    var body: some View {
        Form {
            Toggle("Dark Mode", isOn: $isDarkMode)

            TextField("Benutzername", text: $username)

            Slider(value: $fontSize, in: 12...24, step: 1) {
                Text("Schriftgröße: \(Int(fontSize))")
            }
        }
    }
}

Der String "isDarkMode" ist der Key in UserDefaults. Der Wert wird sofort gespeichert, wenn er sich ändert, und beim nächsten App-Start automatisch geladen.

Was @AppStorage kann — und was nicht

Unterstützte Typen: Bool, Int, Double, String, URL, Data

Nicht unterstützt: Arrays, Dictionaries, eigene Structs, Enums (außer mit RawValue)

Für Enums funktioniert ein Workaround über RawRepresentable:

enum AppTheme: String {
    case light, dark, system
}

struct SettingsView: View {
    @AppStorage("appTheme") private var theme: String = AppTheme.system.rawValue

    private var selectedTheme: AppTheme {
        AppTheme(rawValue: theme) ?? .system
    }
}

Wichtig: @AppStorage ist für kleine Werte gedacht — Einstellungen, Flags, Präferenzen. Speichere keine großen Datenmengen damit. UserDefaults ist nicht für Megabytes ausgelegt.

UserDefaults direkt – für Arrays und mehr

Wenn du Arrays oder Dictionaries speichern willst, greifst du direkt auf UserDefaults zu:

// Speichern
let favoriten = ["artikel-1", "artikel-2", "artikel-3"]
UserDefaults.standard.set(favoriten, forKey: "favoriten")

// Laden
let gespeichert = UserDefaults.standard.stringArray(forKey: "favoriten") ?? []

Für eigene Structs kombinierst du Codable mit JSONEncoder:

struct Bookmark: Codable {
    let slug: String
    let title: String
    let date: Date
}

// Speichern
func saveBookmarks(_ bookmarks: [Bookmark]) {
    if let data = try? JSONEncoder().encode(bookmarks) {
        UserDefaults.standard.set(data, forKey: "bookmarks")
    }
}

// Laden
func loadBookmarks() -> [Bookmark] {
    guard let data = UserDefaults.standard.data(forKey: "bookmarks") else {
        return []
    }
    return (try? JSONDecoder().decode([Bookmark].self, from: data)) ?? []
}

UserDefaults in einer @Observable-Klasse

In der Praxis kapselst du den Zugriff in einer Klasse, die du per .environment() injizierst:

@Observable
@MainActor
final class BookmarkStore {
    private let key = "bookmarks"

    var bookmarks: [String] = [] {
        didSet {
            UserDefaults.standard.set(bookmarks, forKey: key)
        }
    }

    init() {
        bookmarks = UserDefaults.standard.stringArray(forKey: key) ?? []
    }

    func toggle(_ slug: String) {
        if bookmarks.contains(slug) {
            bookmarks.removeAll { $0 == slug }
        } else {
            bookmarks.append(slug)
        }
    }
}

So hast du reaktiven State, der automatisch in UserDefaults persistiert wird.

SwiftData – für echte Datenmodelle

Wenn deine App mehr als Einstellungen speichern muss — Artikel, Notizen, Projekte mit Beziehungen — ist SwiftData die richtige Wahl. Es ist Apples moderner Ersatz für Core Data, direkt in SwiftUI integriert.

Model definieren

import SwiftData

@Model
final class Note {
    var title: String
    var content: String
    var createdAt: Date
    var isPinned: Bool

    init(title: String, content: String) {
        self.title = title
        self.content = content
        self.createdAt = .now
        self.isPinned = false
    }
}

Container einrichten

In deiner App-Struct:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: Note.self)
    }
}

Daten lesen und schreiben

struct NoteListView: View {
    @Query(sort: \Note.createdAt, order: .reverse) private var notes: [Note]
    @Environment(\.modelContext) private var context

    var body: some View {
        NavigationStack {
            List {
                ForEach(notes) { note in
                    VStack(alignment: .leading) {
                        Text(note.title)
                            .font(.headline)
                        Text(note.content)
                            .font(.subheadline)
                            .foregroundStyle(.secondary)
                    }
                }
                .onDelete { indexSet in
                    for index in indexSet {
                        context.delete(notes[index])
                    }
                }
            }
            .navigationTitle("Notizen")
            .toolbar {
                Button("Neu", systemImage: "plus") {
                    let note = Note(title: "Neue Notiz", content: "")
                    context.insert(note)
                }
            }
        }
    }
}

@Query lädt die Daten automatisch und aktualisiert die View bei Änderungen. modelContext übernimmt das Speichern — du musst kein save() aufrufen, SwiftData speichert automatisch.

Filtern mit #Predicate

@Query(
    filter: #Predicate<Note> { $0.isPinned == true },
    sort: \Note.createdAt
)
private var pinnedNotes: [Note]

Welchen Ansatz wählen?

Kriterium@AppStorageUserDefaultsSwiftData
SetupKeineKeineModelContainer
DatentypenPrimitivPrimitiv + CodableKomplexe Modelle
BeziehungenNeinNeinJa
Suche & FilterNeinNeinJa (#Predicate)
DatenmengeWenige KBWenige KBUnbegrenzt
MigrationManuellManuellAutomatisch
Faustregel: Starte mit @AppStorage. Wenn du Arrays brauchst, nimm UserDefaults. Sobald du Beziehungen, Suche oder große Datenmengen hast, wechsle zu SwiftData.

Fazit

Datenpersistenz ist kein Nice-to-have — sie ist das Fundament jeder App, die sich fertig anfühlen soll. Mit @AppStorage für Einstellungen, UserDefaults für einfache Listen und SwiftData für komplexe Modelle hast du drei Werkzeuge, die zusammen jeden Anwendungsfall abdecken. Fang einfach an und skaliere, wenn es nötig wird.

Mehr über unsere App-Entwicklung →


Dieser Artikel wurde zuletzt am 25. März 2026 aktualisiert. Getestet mit Xcode 26 / iOS 26 / Swift 6.

Beitrag teilen