@AppStorage sa SwiftUI — property wrapper para sa pagtatrabaho sa UserDefaults, na awtomatikong nag-sync ng halaga sa UI. Kapag nagbago ang property na idineklara sa pamamagitan ng @AppStorage, ang bagong halaga ay agad na nai-save sa UserDefaults, at kapag ang UserDefaults ay nagbago mula sa labas — ng widget o extension — ang View ay awtomatikong muling iginuhit. Ayon sa Apple Developer Documentation (2025), ang @AppStorage ay sumusuporta sa String, Int, Double, Bool, Data, URL at kanilang mga opsyonal na bersyon, na nagbibigay ng reaktibong pag-iimbak ng mga setting ng user nang walang manu-manong code ng pagmamasid.
Mga Pangunahing Punto
@AppStorage ay isang property wrapper na ipinakilala ng Apple sa iOS 14, na nag-uugnay ng property ng View sa isang key sa UserDefaults. Kapag binabasa ang property, nilo-load ng SwiftUI ang halaga mula sa UserDefaults batay sa tinukoy na key. Kapag nagsusulat — ini-save ang bagong halaga at inaabisuhan ang View na kailangan itong muling iguhit.
Bago ang pagdating ng @AppStorage, ang mga developer ay kailangang manu-manong magbasa ng UserDefaults sa onAppear, mag-subscribe sa UserDefaults.didChangeNotification at mag-update ng @State sa mga pagbabago. Ang @AppStorage ay nag-automate ng buong cycle: isang deklarasyon sa isang linya ay pumapalit sa 15–20 linya ng boilerplate code. Higit pa rito, ang @AppStorage ay nagbibigay ng two-way na synchronisation — kung ang halaga ng UserDefaults ay binago mula sa ibang proseso (hal., App Extension o Widget), ang View ay makakatanggap pa rin ng update.
Sa arkitektura, ang @AppStorage ay ipinatupad bilang DynamicProperty, na nagpapahintulot sa SwiftUI na subaybayan ang mga dependency at muling iguhit ang View kapag nagbago ang naobserbahang halaga. Ginagawa nitong perpekto para sa pag-iimbak ng mga setting ng user: wika ng interface, pag-activate/pag-deactivate ng mga feature, huling napiling tab, username.
Kahit na ang @AppStorage ay gumagamit ng UserDefaults sa ilalim ng hood, ang mga diskarte sa pagtatrabaho sa imbakan ay pangunahing nagkakaiba. Ang UserDefaults ay isang mababang antas na API na nangangailangan ng manu-manong pamamahala ng pagbabasa, pagsusulat at mga abiso ng pagbabago. Ang @AppStorage ay isang SwiftUI abstraction na nagbibigay ng reaktibong pag-uugali mula sa kahon.
Ang UserDefaults ay angkop para sa isang beses na operasyon: pag-load ng mga setting sa startup ng app, pagsusulat ng analytics, pag-cache ng mga token. @AppStorage — para sa mga setting na dapat reaktibong mag-update ng UI: mga switch ng tema, pagpili ng wika, pag-save ng estado ng interface. Ang direktang paggamit ng UserDefaults sa loob ng View ay isang antipattern, dahil hindi nalalaman ng View ang mga pagbabago nang walang karagdagang subscription.
| Parameter | @AppStorage | UserDefaults |
|---|---|---|
| Reaktibidad | Awtomatiko | Nangangailangan ng subscription sa mga abiso |
| Boilerplate | 1 linya bawat property | 15–20 linya bawat property |
| Mga uri | String, Int, Double, Bool, Data, URL | Lahat ng uri + archive na bagay |
| Mga custom na uri | Sa pamamagitan ng RawRepresentable | Sa pamamagitan ng NSKeyedArchiver |
| App Extension | Awtomatikong synchronisation | Manu-manong subscription |
Para sa mga simpleng setting na may reaktibong UI, ang @AppStorage ang mas gustong pagpilian. Para sa mga kumplikadong data (array, diksyunaryo, custom na bagay) gumamit ng kumbinasyon ng UserDefaults na may @State at manu-manong subscription sa mga pagbabago, o lumipat sa SwiftData / Core Data para sa nakaayos na imbakan.
Ang @AppStorage ay sumusuporta sa mga karaniwang uri na direktang mai-serialize ng UserDefaults: String, Int, Double, Bool, Data, URL. Para sa bawat uri ay may opsyonal na bersyon (String?, Int?, Double?, Bool?, Data?, URL?), na nagpapahintulot sa pag-iba sa pagitan ng “hindi nakatakda” at “walang laman na halaga”.
Para sa pag-iimbak ng mga custom na uri na sumusunod sa RawRepresentable protocol, ang @AppStorage ay awtomatikong gumagana. Kung ang enum ay may rawValue na uri ng String o Int, maaari itong gamitin nang direkta: @AppStorage("theme") var theme: AppTheme = .system. Awtomatikong sine-serialize/deserialize ng SwiftUI ang halaga sa pamamagitan ng 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("Inilunsad \(launchCount) beses")
}
}
}
Sa halimbawa, ginagamit ang iba’t ibang uri ng @AppStorage: String na may default na halaga na “Guest”, Int para sa startup counter, Bool para sa dark theme, enum AppTheme na may rawValue na uri ng String at opsyonal na Date? para sa huling oras ng pagbukas. Ang bawat property ay naka-link sa UserDefaults key na tinukoy bilang unang argumento. Ang default na halaga ay ginagamit kung ang key ay wala sa imbakan sa unang pagtakbo.
Isa sa mga pangunahing bentahe ng @AppStorage — awtomatikong pagmamasid sa mga pagbabago ng UserDefaults mula sa anumang pinagmulan. Kung ang App Extension o Widget ay magbago ng halaga, ang @AppStorage sa parent na application ay makakatanggap ng abiso at muling iguguhit ang View. Ito ay nakakamit sa pamamagitan ng mekanismong KVO (Key-Value Observing), na awtomatikong itinatakda ng @AppStorage sa UserDefaults.didChangeNotification.
Sa praktika, nangangahulugan ito na kung babaguhin ng user ang isang setting sa Widget (hal., i-on ang dark theme), agad na kukunin ng application ang pagbabagong iyon. Ganoon din gumagana ang synchronisation sa pagitan ng pangunahing application at Share Extension, Watch App o Today Widget. Hindi kailangang magsulat ng code ang developer para sa inter-process na pagpapalitan ng data — awtomatikong ginagawa ito ng @AppStorage.
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("Binago ang dark mode sa \(newValue)")
}
}
}
}
Ang Toggle ay konektado sa $isDarkMode sa pamamagitan ng @AppStorage. Kapag inilipat, ang halaga ay awtomatikong nai-save sa UserDefaults sa ilalim ng key na “isDarkMode”. Ang modifier na .onChange ay nagpapahintulot ng pagsasagawa ng side action sa pagbabago — halimbawa, pagpapadala ng analytics o pag-update ng UI ng iba pang mga screen. Kung babaguhin ng Widget ang parehong key, tatawagin din ng @AppStorage ang onChange, na tinitiyak ang consistency ng estado.
Tingnan natin ang isang kumpletong screen ng mga setting ng application na gumagamit ng @AppStorage para iimbak ang lahat ng configuration. Ang form ay naglalaman ng mga seksyon na may iba’t ibang uri ng mga setting: mga text field, switch, counter — lahat ng halaga ay awtomatikong nai-save sa 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("Profile")) {
TextField("Display name", text: $displayName)
}
Section(header: Text("Mga Kagustuhan")) {
Toggle("Enable notifications",
isOn: $notificationsEnabled)
Stepper("Max results: \(maxResults)",
value: $maxResults,
in: 10...100,
step: 5)
}
Section {
Button("I-reset ang mga setting") {
UserDefaults.standard.removePersistentDomain(
forName: Bundle.main.bundleIdentifier!)
}
.tint(.red)
}
}
.navigationTitle("Settings")
}
}
}
Ang form ay naglalaman ng apat na @AppStorage na property ng iba’t ibang uri: String para sa pangalan, Bool para sa mga notification, Int para sa bilang ng mga resulta at String para sa napiling tab. Ang lahat ng kontrol ay konektado sa mga property sa pamamagitan ng Binding ($displayName, $notificationsEnabled atbp.). Ang button na “Reset settings” ay nagre-reset ng lahat ng UserDefaults, binubura ang domain ng application — pagkatapos nito, awtomatikong babalik ang @AppStorage sa mga default na halaga.
struct SharedSettingsView: View {
let sharedDefaults = UserDefaults(suiteName: "group.com.example.app")
@AppStorage("widgetTheme", store: UserDefaults(suiteName: "group.com.example.app")!)
var widgetTheme: String = "system"
@AppStorage("widgetColor", store: UserDefaults(suiteName: "group.com.example.app")!)
var widgetColor: String = "blue"
var body: some View {
Form {
Picker("Widget theme", selection: $widgetTheme) {
Text("System").tag("system")
Text("Light").tag("light")
Text("Dark").tag("dark")
}
Picker("Accent color", selection: $widgetColor) {
Text("Blue").tag("blue")
Text("Green").tag("green")
Text("Red").tag("red")
}
}
}
}
Para sa App Group (shared storage sa pagitan ng application at extensions) ang @AppStorage ay tumatanggap ng parameter na store: UserDefaults(suiteName:). Ang mga halaga ay nai-save sa isang shared container na accessible sa pangunahing application, Widget, Watch App at iba pang extension ng parehong grupo. Maaaring basahin ng Widget ang mga setting na ito, at sa pagbabago sa application, ang Widget ay awtomatikong nag-a-update sa pamamagitan ng mekanismo ng pagmamasid ng UserDefaults.
Mga Madalas Itanong
Ang @State ay nag-iimbak ng halaga lamang sa memory at nire-reset kapag ni-restart ang application. Ang @AppStorage ay nagse-save ng halaga sa UserDefaults at ibinabalik ito sa susunod na pagtakbo. Gamitin ang @State para sa pansamantalang data ng screen, @AppStorage — para sa mga setting na dapat tumagal sa restart.
Oo, kung ang Enum ay nagpapatupad ng RawRepresentable protocol na may rawValue na uri ng String o Int. Halimbawa: @AppStorage("theme") var theme: AppTheme = .system. Awtomatikong sine-serialize ng SwiftUI ang enum sa pamamagitan ng rawValue at ibinabalik ito kapag na-load.
Tawagan ang UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!) para sa standard storage o removeObject(forKey:) para sa partikular na key. Pagkatapos ng paglilinis, lahat ng @AppStorage property ay babalik sa mga default na halaga na tinukoy sa deklarasyon.
Oo, para sa synchronisation sa pagitan ng application at extensions gamitin ang App Group: @AppStorage("key", store: UserDefaults(suiteName: "group.com.example.app")!). Ang Widget, Share Extension at Watch App ay maaaring magbasa at magsulat sa parehong UserDefaults, at ang mga pagbabago ay awtomatikong sinusubaybayan.
Ang @AppStorage ay gumagamit ng UserDefaults, na idinisenyo para sa maliit na dami ng data: mga setting, token, counter. Ang inirerekomendang limitasyon — hanggang 100 KB bawat application. Para sa nakaayos o malalaking data (array ng mga bagay, media file) gamitin ang SwiftData, Core Data o file system.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din