@AppStorage in SwiftUI — property wrapper voor het werken met UserDefaults, die automatisch de waarde synchroniseert met de UI. Bij wijziging van een eigenschap gedeclareerd via @AppStorage, wordt de nieuwe waarde onmiddellijk opgeslagen in UserDefaults, en wanneer UserDefaults extern wordt gewijzigd — door een widget of extensie — wordt de View automatisch opnieuw getekend. Volgens Apple Developer Documentation (2025), ondersteunt @AppStorage String, Int, Double, Bool, Data, URL en hun optionele versies, wat zorgt voor reactieve opslag van gebruikersinstellingen zonder handmatige observatiecode.
Belangrijkste punten
@AppStorage is een property wrapper geïntroduceerd door Apple in iOS 14, die een eigenschap van een View koppelt aan een sleutel in UserDefaults. Bij het lezen van de eigenschap laadt SwiftUI de waarde uit UserDefaults op basis van de opgegeven sleutel. Bij het schrijven — slaat het de nieuwe waarde op en stelt het de View op de hoogte van de noodzaak tot opnieuw tekenen.
Vóór de komst van @AppStorage moesten ontwikkelaars handmatig UserDefaults lezen in onAppear, zich abonneren op de UserDefaults.didChangeNotification-melding en @State bijwerken bij wijzigingen. @AppStorage automatiseert de hele cyclus: een declaratie op één regel vervangt 15–20 regels boilerplate-code. Bovendien zorgt @AppStorage voor bidirectionele synchronisatie — als de UserDefaults-waarde wordt gewijzigd vanuit een ander proces (bijv. App Extension of Widget), ontvangt de View nog steeds de update.
Architectonisch is @AppStorage geïmplementeerd als DynamicProperty, waardoor SwiftUI afhankelijkheden kan volgen en de View opnieuw kan tekenen bij wijziging van de geobserveerde waarde. Dit maakt het ideaal voor het opslaan van gebruikersinstellingen: interfacetaal, in-/uitschakelen van functies, laatst geselecteerd tabblad, gebruikersnaam.
Hoewel @AppStorage onder de motorkap UserDefaults gebruikt, verschillen de benaderingen van opslag fundamenteel. UserDefaults is een laag-niveau API die handmatig beheer van lezen, schrijven en wijzigingsmeldingen vereist. @AppStorage is een SwiftUI-abstractie die uit de doos reactief gedrag biedt.
UserDefaults is geschikt voor eenmalige bewerkingen: laden van instellingen bij het starten van de app, schrijven van analyses, cachen van tokens. @AppStorage — voor instellingen die reactief de UI moeten bijwerken: themaschakelaars, taalkeuze, opslaan van interface-staat. Direct gebruik van UserDefaults binnen een View is een antipatroon, omdat de View niet op de hoogte raakt van wijzigingen zonder extra abonnement.
| Parameter | @AppStorage | UserDefaults |
|---|---|---|
| Reactiviteit | Automatisch | Vereist abonnement op meldingen |
| Boilerplate | 1 regel per eigenschap | 15–20 regels per eigenschap |
| Typen | String, Int, Double, Bool, Data, URL | Alle typen + gearchiveerde objecten |
| Aangepaste typen | Via RawRepresentable | Via NSKeyedArchiver |
| App Extension | Automatische synchronisatie | Handmatig abonnement |
Voor eenvoudige instellingen met reactieve UI is @AppStorage de voorkeurskeuze. Voor complexe gegevens (arrays, woordenboeken, aangepaste objecten) gebruikt u een combinatie van UserDefaults met @State en handmatige abonnementen op wijzigingen, of stapt u over op SwiftData / Core Data voor gestructureerde opslag.
@AppStorage ondersteunt de standaardtypen die UserDefaults direct kan serialiseren: String, Int, Double, Bool, Data, URL. Voor elk type is er een optionele versie (String?, Int?, Double?, Bool?, Data?, URL?), waarmee onderscheid kan worden gemaakt tussen „niet ingesteld” en „lege waarde”.
Voor het opslaan van aangepaste typen die voldoen aan het RawRepresentable-protocol, werkt @AppStorage ook automatisch. Als een enum een rawValue van het type String of Int heeft, kan het direct worden gebruikt: @AppStorage("theme") var theme: AppTheme = .system. SwiftUI serialiseert/deserialiseert automatisch de waarde via rawValue.
enum AppTheme: String {
case system, light, dark
}
struct SettingsView: View {
@AppStorage("username") var username: String = "Guest"
@AppStorage("launchCount") var launchCount: Int = 0
@AppStorage("isDarkMode") var isDarkMode: Bool = false
@AppStorage("appTheme") var theme: AppTheme = .system
@AppStorage("lastOpened") var lastOpened: Date? = nil
var body: some View {
Form {
TextField("Username", text: $username)
Toggle("Dark mode", isOn: $isDarkMode)
Text("Gestart \(launchCount) keer")
}
}
}
In het voorbeeld worden verschillende @AppStorage-typen gebruikt: String met de standaardwaarde „Guest”, Int voor de startteller, Bool voor het donkere thema, enum AppTheme met rawValue van het type String en optionele Date? voor de laatste openingstijd. Elke eigenschap is gekoppeld aan een UserDefaults-sleutel die als eerste argument is opgegeven. De standaardwaarde wordt gebruikt als de sleutel bij de eerste start niet in de opslag aanwezig is.
Een van de belangrijkste voordelen van @AppStorage — het automatisch observeren van UserDefaults-wijzigingen vanuit elke bron. Als een App Extension of Widget een waarde wijzigt, ontvangt @AppStorage in de bovenliggende applicatie een melding en tekent de View opnieuw. Dit wordt bereikt via het KVO-mechanisme (Key-Value Observing), dat @AppStorage automatisch instelt op UserDefaults.didChangeNotification.
In de praktijk betekent dit dat als een gebruiker een instelling wijzigt in een Widget (bijv. het donkere thema inschakelt), de applicatie deze wijziging onmiddellijk overneemt. Zo werkt ook de synchronisatie tussen de hoofdapplicatie en Share Extension, Watch App of Today Widget. De ontwikkelaar hoeft geen code te schrijven voor interprocesgegevensuitwisseling — @AppStorage doet dit automatisch.
struct ThemeSettingView: View {
@AppStorage("isDarkMode") var isDarkMode: Bool = false
var body: some View {
VStack {
Toggle("Dark Mode", isOn: $isDarkMode)
.onChange(of: isDarkMode) { oldValue, newValue in
print("Donkere modus gewijzigd naar \(newValue)")
}
}
}
}
Toggle is via @AppStorage gekoppeld aan $isDarkMode. Bij het omschakelen wordt de waarde automatisch opgeslagen in UserDefaults onder de sleutel „isDarkMode”. De modifier .onChange maakt het mogelijk om een nevenactie uit te voeren bij wijziging — bijvoorbeeld het verzenden van analytics of het bijwerken van de UI van andere schermen. Als Widget dezelfde sleutel wijzigt, roept @AppStorage ook onChange aan, wat de consistentie van de status waarborgt.
Laten we een volledig instellingenscherm van een applicatie bekijken dat @AppStorage gebruikt voor het opslaan van alle configuraties. Het formulier bevat secties met verschillende soorten instellingen: tekstvelden, schakelaars, tellers — alle waarden worden automatisch opgeslagen in UserDefaults.
struct AppSettingsView: View {
@AppStorage("displayName") var displayName = ""
@AppStorage("notificationsEnabled") var notificationsEnabled = true
@AppStorage("maxResults") var maxResults = 25
@AppStorage("selectedTab") var selectedTab = "home"
var body: some View {
NavigationStack {
Form {
Section(header: Text("Profiel")) {
TextField("Display name", text: $displayName)
}
Section(header: Text("Voorkeuren")) {
Toggle("Enable notifications",
isOn: $notificationsEnabled)
Stepper("Max results: \(maxResults)",
value: $maxResults,
in: 10...100,
step: 5)
}
Section {
Button("Instellingen resetten") {
UserDefaults.standard.removePersistentDomain(
forName: Bundle.main.bundleIdentifier!)
}
.tint(.red)
}
}
.navigationTitle("Settings")
}
}
}
Het formulier bevat vier @AppStorage-eigenschappen van verschillende typen: String voor de naam, Bool voor meldingen, Int voor het aantal resultaten en String voor het geselecteerde tabblad. Alle besturingselementen zijn via Binding aan de eigenschappen gekoppeld ($displayName, $notificationsEnabled enz.). De knop „Reset settings” reset alle UserDefaults door het domein van de applicatie te verwijderen — daarna keert @AppStorage automatisch terug naar de standaardwaarden.
struct SharedSettingsView: View {
let sharedDefaults = UserDefaults(suiteName: "group.com.example.app")
@AppStorage("widgetTheme", store: UserDefaults(suiteName: "group.com.example.app")!)
var widgetTheme: String = "systeem"
@AppStorage("widgetColor", store: UserDefaults(suiteName: "group.com.example.app")!)
var widgetColor: String = "blauw"
var body: some View {
Form {
Picker("Widget theme", selection: $widgetTheme) {
Text("Systeem").tag("system")
Text("Licht").tag("licht")
Text("Donker").tag("donker")
}
Picker("Accent color", selection: $widgetColor) {
Text("Blauw").tag("blue")
Text("Groen").tag("groen")
Text("Rood").tag("rood")
}
}
}
}
Voor App Group (gedeelde opslag tussen de applicatie en extensies) accepteert @AppStorage de parameter store: UserDefaults(suiteName:). Waarden worden opgeslagen in een gedeelde container die toegankelijk is voor de hoofdapplicatie, Widget, Watch App en andere extensies van dezelfde groep. Widget kan deze instellingen lezen en bij wijziging in de applicatie wordt Widget automatisch bijgewerkt via het UserDefaults-observeringsmechanisme.
Veelgestelde vragen
@State slaat de waarde alleen in het geheugen op en wordt gereset bij het opnieuw starten van de applicatie. @AppStorage slaat de waarde op in UserDefaults en herstelt deze bij de volgende start. Gebruik @State voor tijdelijke schermgegevens, @AppStorage voor instellingen die een herstart moeten overleven.
Ja, als Enum het RawRepresentable-protocol implementeert met rawValue van het type String of Int. Voorbeeld: @AppStorage("theme") var theme: AppTheme = .system. SwiftUI serialiseert automatisch de enum via rawValue en herstelt deze bij het laden.
Roep UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!) aan voor de standaardopslag of removeObject(forKey:) voor een specifieke sleutel. Na het wissen keren alle @AppStorage-eigenschappen terug naar de standaardwaarden zoals gespecificeerd in de declaratie.
Ja, gebruik voor synchronisatie tussen de applicatie en extensies App Group: @AppStorage("key", store: UserDefaults(suiteName: "group.com.example.app")!). Widget, Share Extension en Watch App kunnen lezen en schrijven in dezelfde UserDefaults, en wijzigingen worden automatisch gevolgd.
@AppStorage gebruikt UserDefaults, dat is bedoeld voor kleine hoeveelheden gegevens: instellingen, tokens, tellers. De aanbevolen limiet is tot 100 KB per applicatie. Voor gestructureerde of grote gegevens (objectarrays, mediabestanden) gebruikt u SwiftData, Core Data of het bestandssysteem.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook