@AppStorage în SwiftUI — ce este, UserDefaults și stocarea setărilor

Autor: IT Sectr Publicat: 2026-06-25 Timp de citire: 7 min

@AppStorage în SwiftUI — property wrapper pentru lucrul cu UserDefaults, care sincronizează automat valoarea cu UI. La modificarea proprietății declarate prin @AppStorage, noua valoare este imediat salvată în UserDefaults, iar când UserDefaults se schimbă din exterior — printr-un widget sau extensie — View se redesenează automat. Conform Apple Developer Documentation (2025), @AppStorage suportă String, Int, Double, Bool, Data, URL și versiunile lor opționale, asigurând stocarea reactivă a setărilor utilizatorului fără cod de observare manual.

Principalele

  • @AppStorage — property wrapper pentru lucrul reactiv cu UserDefaults în SwiftUI
  • Autosalvare — valoarea se scrie în UserDefaults la fiecare modificare
  • Actualizare automată UI — View se redesenează la modificarea UserDefaults din orice sursă
  • Tipuri suportate: String, Int, Double, Bool, Data, URL și versiuni opționale
  • Valoarea implicită se stabilește în declarație și se folosește la prima pornire

Ce este @AppStorage în SwiftUI?

@AppStorage este un property wrapper introdus de Apple în iOS 14, care leagă o proprietate View de o cheie din UserDefaults. La citirea proprietății, SwiftUI încarcă valoarea din UserDefaults după cheia specificată. La scriere — salvează noua valoare și notifică View-ul despre necesitatea redesenării.

Înainte de apariția @AppStorage, dezvoltatorii trebuiau să citească manual UserDefaults în onAppear, să se aboneze la notificarea UserDefaults.didChangeNotification și să actualizeze @State la modificări. @AppStorage automatizează întregul ciclu: o declarație pe o singură linie înlocuiește 15–20 de linii de cod boilerplate. Mai mult, @AppStorage asigură sincronizare bidirecțională — dacă valoarea UserDefaults este modificată dintr-un alt proces (de exemplu, App Extension sau Widget), View-ul va primi totuși actualizarea.

Arhitectural, @AppStorage este implementat ca DynamicProperty, permițând SwiftUI să urmărească dependențele și să redeseneze View-ul la modificarea valorii observate. Acest lucru îl face ideal pentru stocarea setărilor utilizatorului: limba interfeței, activarea/dezactivarea funcțiilor, ultimul tab selectat, numele utilizatorului.

@AppStorage vs UserDefaults: comparație

Deși @AppStorage folosește UserDefaults sub capotă, abordările de lucru cu stocarea diferă fundamental. UserDefaults este o API de nivel scăzut care necesită gestionarea manuală a citirii, scrierii și notificărilor de modificare. @AppStorage este o abstractizare SwiftUI care oferă comportament reactiv din cutie.

UserDefaults este potrivit pentru operații unice: încărcarea setărilor la pornirea aplicației, scrierea analiticelor, cache-ul token-urilor. @AppStorage — pentru setări care trebuie să actualizeze reactiv UI: comutatoare de teme, selectarea limbii, salvarea stării interfeței. Utilizarea directă a UserDefaults în interiorul View-ului este un antipattern, deoarece View-ul nu află despre modificări fără o abonare suplimentară.

Parametru@AppStorageUserDefaults
ReactivitateAutomatăNecesită abonare la notificări
Boilerplate1 linie per proprietate15–20 linii per proprietate
TipuriString, Int, Double, Bool, Data, URLToate tipurile + obiecte arhivate
Tipuri personalizatePrin RawRepresentablePrin NSKeyedArchiver
App ExtensionSincronizare automatăAbonare manuală

Pentru setări simple cu UI reactiv, @AppStorage este alegerea preferată. Pentru date complexe (tablouri, dicționare, obiecte personalizate) folosiți combinația UserDefaults cu @State și abonare manuală la modificări, sau treceți la SwiftData / Core Data pentru stocare structurată.

Tipuri de date suportate

@AppStorage suportă tipurile standard pe care UserDefaults le poate serializa direct: String, Int, Double, Bool, Data, URL. Pentru fiecare tip există o versiune opțională (String?, Int?, Double?, Bool?, Data?, URL?), permițând diferențierea între „nesetat” și „valoare goală”.

Pentru stocarea tipurilor personalizate conforme cu protocolul RawRepresentable, @AppStorage funcționează și automat. Dacă enum are rawValue de tip String sau Int, poate fi folosit direct: @AppStorage("theme") var theme: AppTheme = .system. SwiftUI serializează/deserializează automat valoarea prin rawValue.

swift
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("Lansat de \(launchCount) ori")
        }
    }
}

În exemplu sunt folosite diferite tipuri de @AppStorage: String cu valoarea implicită „Guest”, Int pentru contorul de porniri, Bool pentru tema întunecată, enum AppTheme cu rawValue de tip String și Date? opțional pentru ultima deschidere. Fiecare proprietate este legată de cheia UserDefaults specificată ca prim argument. Valoarea implicită este folosită dacă cheia lipsește din stocare la prima pornire.

Observarea modificărilor Store

Unul dintre avantajele cheie ale @AppStorage — observarea automată a modificărilor UserDefaults din orice sursă. Dacă App Extension sau Widget modifică o valoare, @AppStorage în aplicația părinte primește notificare și redesenează View-ul. Acest lucru se realizează prin mecanismul KVO (Key-Value Observing), pe care @AppStorage îl setează automat pe UserDefaults.didChangeNotification.

În practică, aceasta înseamnă că dacă utilizatorul modifică o setare în Widget (de exemplu, activează tema întunecată), aplicația preia imediat această modificare. Similar funcționează sincronizarea între aplicația principală și Share Extension, Watch App sau Today Widget. Dezvoltatorul nu trebuie să scrie cod pentru schimbul de date interproces — @AppStorage face acest lucru automat.

swift
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("Modul întunecat schimbat la \(newValue)")
                }
        }
    }
}

Toggle este legat de $isDarkMode prin @AppStorage. La comutare, valoarea este automat salvată în UserDefaults sub cheia „isDarkMode”. Modificatorul .onChange permite executarea unei acțiuni secundare la modificare — de exemplu, trimiterea de analitice sau actualizarea UI-ului altor ecrane. Dacă Widget modifică aceeași cheie, @AppStorage va apela și onChange, asigurând consistența stării.

Exemple de cod @AppStorage

Să examinăm un ecran complet de setări al aplicației care folosește @AppStorage pentru stocarea tuturor configurațiilor. Formularul conține secțiuni cu diferite tipuri de setări: câmpuri text, comutatoare, contoare — toate valorile sunt salvate automat în UserDefaults.

swift
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("Profil")) {
                    TextField("Display name", text: $displayName)
                }

                Section(header: Text("Preferințe")) {
                    Toggle("Enable notifications",
                           isOn: $notificationsEnabled)
                    Stepper("Max results: \(maxResults)",
                           value: $maxResults,
                           in: 10...100,
                           step: 5)
                }

                Section {
                    Button("Resetează setările") {
                        UserDefaults.standard.removePersistentDomain(
                            forName: Bundle.main.bundleIdentifier!)
                    }
                    .tint(.red)
                }
            }
            .navigationTitle("Settings")
        }
    }
}

Formularul conține patru proprietăți @AppStorage de diferite tipuri: String pentru nume, Bool pentru notificări, Int pentru numărul de rezultate și String pentru tab-ul selectat. Toate controalele sunt legate de proprietăți prin Binding ($displayName, $notificationsEnabled etc.). Butonul „Reset settings” resetează toate UserDefaults, ștergând domeniul aplicației — după aceasta, @AppStorage revine automat la valorile implicite.

Sincronizarea @AppStorage cu App Group

swift
struct SharedSettingsView: View {
    let sharedDefaults = UserDefaults(suiteName: "group.com.example.app")

    @AppStorage("widgetTheme", store: UserDefaults(suiteName: "group.com.example.app")!)
    var widgetTheme: String = "sistem"

    @AppStorage("widgetColor", store: UserDefaults(suiteName: "group.com.example.app")!)
    var widgetColor: String = "albastru"

    var body: some View {
        Form {
            Picker("Widget theme", selection: $widgetTheme) {
                Text("Sistem").tag("system")
                Text("Luminos").tag("luminos")
                Text("Întunecat").tag("Întunecat")
            }
            Picker("Accent color", selection: $widgetColor) {
                Text("Albastru").tag("blue")
                Text("Verde").tag("verde")
                Text("Roșu").tag("roșu")
            }
        }
    }
}

Pentru App Group (stocare partajată între aplicație și extensii) @AppStorage acceptă parametrul store: UserDefaults(suiteName:). Valorile sunt salvate într-un container comun accesibil aplicației principale, Widget, Watch App și altor extensii din același grup. Widget poate citi aceste setări, iar la modificarea în aplicație, Widget se actualizează automat prin mecanismul de observare UserDefaults.

Întrebări frecvente

Care este diferența dintre @AppStorage și @State?

@State stochează valoarea doar în memorie și se resetează la repornirea aplicației. @AppStorage salvează valoarea în UserDefaults și o restabilește la următoarea pornire. Folosiți @State pentru date temporare ale ecranului, @AppStorage — pentru setări care trebuie să supraviețuiască repornirii.

Se poate folosi @AppStorage cu Enum?

Da, dacă Enum implementează protocolul RawRepresentable cu rawValue de tip String sau Int. Exemplu: @AppStorage("theme") var theme: AppTheme = .system. SwiftUI serializează automat enum-ul prin rawValue și îl restabilește la încărcare.

Cum se șterg toate valorile @AppStorage?

Apelați UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!) pentru stocarea standard sau removeObject(forKey:) pentru o cheie specifică. După ștergere, toate proprietățile @AppStorage revin la valorile implicite specificate în declarație.

Funcționează @AppStorage cu App Extensions?

Da, pentru sincronizarea între aplicație și extensii folosiți App Group: @AppStorage("key", store: UserDefaults(suiteName: "group.com.example.app")!). Widget, Share Extension și Watch App pot citi și scrie în același UserDefaults, iar modificările sunt urmărite automat.

Ce volum de date poate fi stocat în @AppStorage?

@AppStorage folosește UserDefaults, care este destinat volumelor mici de date: setări, token-uri, contoare. Limita recomandată — până la 100 KB per aplicație. Pentru date structurate sau mari (tablouri de obiecte, fișiere media) utilizați SwiftData, Core Data sau sistemul de fișiere.

Rezumat

  • @AppStorage — property wrapper pentru stocarea reactivă a setărilor în UserDefaults
  • Autosalvare și actualizare automată a UI la modificarea valorii din orice sursă
  • Suportă String, Int, Double, Bool, Data, URL și RawRepresentable enums
  • Valoarea implicită se stabilește în declarație și se restabilește la prima pornire
  • App Group permite sincronizarea @AppStorage între aplicație și extensii
  • UserDefaults este potrivit doar pentru volume mici de date — până la 100 KB
  • Folosiți @AppStorage pentru setările utilizatorului, @State — pentru stări temporare ale ecranului

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și