SwiftUI'daki @AppStorage, UserDefaults ile çalışmak için kullanılan ve değeri otomatik olarak UI ile senkronize eden bir property wrapper'dır. @AppStorage ile bildirilen bir özellik değiştiğinde, yeni değer hemen UserDefaults'a kaydedilir ve UserDefaults dışarıdan — bir widget veya uzantı tarafından — değiştirildiğinde View otomatik olarak yeniden çizilir. Apple Developer Documentation (2025)'a göre, @AppStorage String, Int, Double, Bool, Data, URL ve bunların isteğe bağlı sürümlerini destekleyerek, manuel izleme kodu olmadan kullanıcı ayarlarının reaktif depolanmasını sağlar.
Önemli Noktalar
@AppStorage, Apple tarafından iOS 14'te tanıtılan ve bir View özelliğini UserDefaults'taki bir anahtara bağlayan bir property wrapper'dır. Özellik okunurken, SwiftUI belirtilen anahtarla UserDefaults'tan değeri yükler. Yazarken, yeni değeri kaydeder ve View'a yeniden çizilmesi gerektiğini bildirir.
@AppStorage'den önce, geliştiricilerin onAppear içinde manuel olarak UserDefaults'ı okuması, UserDefaults.didChangeNotification'a abone olması ve değişikliklerde @State'i güncellemesi gerekiyordu. @AppStorage tüm döngüyü otomatikleştirir: tek satırlık bir bildirim, 15-20 satırlık kalıp kodu yerine geçer. Ayrıca, @AppStorage çift yönlü senkronizasyon sağlar — UserDefaults değeri başka bir işlemden (App Extension veya Widget gibi) değişse bile View güncellemeyi alır.
Mimari olarak, @AppStorage DynamicProperty olarak uygulanır ve SwiftUI'nin bağımlılıkları izlemesine ve gözlemlenen değer değiştiğinde View'i yeniden çizmesine olanak tanır. Bu, onu kullanıcı ayarlarını (arayüz dili, özellikleri etkinleştirme/devre dışı bırakma, son seçilen sekme, kullanıcı adı) depolamak için ideal hale getirir.
@AppStorage dahili olarak UserDefaults kullansa da, depolama ile çalışma yaklaşımları temelde farklıdır. UserDefaults, okuma, yazma ve değişiklik bildirimlerinin manuel yönetimini gerektiren düşük seviyeli bir API'dir. @AppStorage, kutudan çıktığı gibi reaktif davranış sağlayan bir SwiftUI soyutlamasıdır.
UserDefaults tek seferlik işlemler için uygundur: uygulama başlangıcında ayarları yükleme, analitik yazma, tokenleri önbelleğe alma. @AppStorage, UI'yi reaktif olarak güncellemesi gereken ayarlar içindir: tema değiştiricileri, dil seçimi, arayüz durumunu kaydetme. Bir View içinde doğrudan UserDefaults kullanmak bir anti-örnektir, çünkü View ek abonelik olmadan değişikliklerden haberdar olmaz.
| Parametre | @AppStorage | UserDefaults |
|---|---|---|
| Reaktivite | Otomatik | Bildirimlere abonelik gerekli |
| Kalıp kod | Özellik başına 1 satır | Özellik başına 15-20 satır |
| Türler | String, Int, Double, Bool, Data, URL | Tüm türler + arşivlenmiş nesneler |
| Özel türler | RawRepresentable ile | NSKeyedArchiver ile |
| App Extension | Otomatik senkronizasyon | Manuel abonelik |
Reaktif UI ile basit ayarlar için @AppStorage tercih edilen seçimdir. Karmaşık veriler (diziler, sözlükler, özel nesneler) için UserDefaults'ı @State ve manuel değişiklik aboneliği ile kombinasyon halinde kullanın veya yapılandırılmış depolama için SwiftData / Core Data'ya geçin.
@AppStorage, UserDefaults'ın doğrudan serileştirebileceği standart türleri destekler: String, Int, Double, Bool, Data, URL. Her tür için isteğe bağlı bir sürüm (String?, Int?, Double?, Bool?, Data?, URL?) bulunur ve "ayarlanmamış" ile "boş değer" arasında ayrım yapmayı sağlar.
RawRepresentable protokolüne uyan özel türleri depolamak için @AppStorage de otomatik olarak çalışır. Bir enum'un rawValue'si String veya Int türündeyse, doğrudan kullanılabilir: @AppStorage("theme") var theme: AppTheme = .system. SwiftUI, rawValue aracılığıyla değeri otomatik olarak serileştirir/deserileştirir.
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("\(launchCount) kez başlatıldı")
}
}
}
Örnek, farklı @AppStorage türlerini kullanır: varsayılan değer "Guest" ile String, başlatma sayacı için Int, karanlık tema için Bool, String türünde rawValue ile AppTheme enum ve son açılma zamanı için isteğe bağlı Date?. Her özellik, ilk argüman olarak belirtilen bir UserDefaults anahtarına bağlıdır. İlk başlatmada anahtar depoda yoksa varsayılan değer kullanılır.
@AppStorage'in temel avantajlarından biri, UserDefaults değişikliklerini herhangi bir kaynaktan otomatik olarak izlemesidir. Bir App Extension veya Widget bir değeri değiştirirse, üst uygulamadaki @AppStorage bildirimi alır ve View'i yeniden çizer. Bu, @AppStorage'in UserDefaults.didChangeNotification üzerinde otomatik olarak kurduğu KVO (Key-Value Observing) mekanizması aracılığıyla elde edilir.
Pratikte bu, kullanıcı bir Widget'ta bir ayarı değiştirirse (örneğin, karanlık temayı etkinleştirirse), uygulamanın değişikliği hemen yakaladığı anlamına gelir. Aynı senkronizasyon ana uygulama ile Share Extension, Watch App veya Today Widget arasında çalışır. Geliştiricinin işlemler arası veri alışverişi için kod yazması gerekmez — @AppStorage bunu otomatik olarak yapar.
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("Karanlık mod \(newValue) olarak değiştirildi")
}
}
}
}
Toggle, @AppStorage aracılığıyla $isDarkMode'a bağlıdır. Değiştirildiğinde, değer otomatik olarak "isDarkMode" anahtarı altında UserDefaults'a kaydedilir. .onChange değiştiricisi, değişiklikte bir yan etki gerçekleştirmeye olanak tanır — örneğin, analitik gönderme veya diğer ekranların UI'ını güncelleme. Bir Widget aynı anahtarı değiştirirse, @AppStorage de onChange'i tetikleyerek durum tutarlılığını sağlar.
Tüm yapılandırmaları depolamak için @AppStorage kullanan tam teşekküllü bir uygulama ayarları ekranını inceleyelim. Form, farklı ayar türlerine sahip bölümler içerir: metin alanları, anahtarlar, sayaçlar — tüm değerler otomatik olarak UserDefaults'a kaydedilir.
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("Tercihler")) {
Toggle("Enable notifications",
isOn: $notificationsEnabled)
Stepper("Max results: \(maxResults)",
value: $maxResults,
in: 10...100,
step: 5)
}
Section {
Button("Ayarları sıfırla") {
UserDefaults.standard.removePersistentDomain(
forName: Bundle.main.bundleIdentifier!)
}
.tint(.red)
}
}
.navigationTitle("Settings")
}
}
}
Form, farklı türlerde dört @AppStorage özelliği içerir: ad için String, bildirimler için Bool, sonuç sayısı için Int ve seçilen sekme için String. Tüm kontroller, Binding ($displayName, $notificationsEnabled, vb.) aracılığıyla özelliklere bağlıdır. "Reset settings" düğmesi, uygulama alanını kaldırarak tüm UserDefaults'ı temizler — bundan sonra @AppStorage otomatik olarak varsayılan değerlere döner.
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 = "mavi"
var body: some View {
Form {
Picker("Widget theme", selection: $widgetTheme) {
Text("Sistem").tag("system")
Text("Açık").tag("açık")
Text("Karanlık").tag("karanlık")
}
Picker("Accent color", selection: $widgetColor) {
Text("Mavi").tag("blue")
Text("Yeşil").tag("yeşil")
Text("Kırmızı").tag("kırmızı")
}
}
}
}
App Group (uygulama ve uzantılar arasında paylaşılan depolama) için @AppStorage store parametresini kabul eder: UserDefaults(suiteName:). Değerler, ana uygulama, Widget, Watch App ve aynı gruptaki diğer uzantılar tarafından erişilebilen paylaşılan kapsayıcıda saklanır. Bir Widget bu ayarları okuyabilir ve uygulamada değiştiklerinde, Widget UserDefaults izleme mekanizması aracılığıyla otomatik olarak güncellenir.
Sıkça Sorulan Sorular
@State değeri yalnızca bellekte saklar ve uygulama yeniden başlatıldığında sıfırlanır. @AppStorage değeri UserDefaults'a kaydeder ve bir sonraki başlatmada geri yükler. Geçici ekran verileri için @State, yeniden başlatmadan sonra kalıcı olması gereken ayarlar için @AppStorage kullanın.
Evet, Enum String veya Int türünde rawValue ile RawRepresentable protokolünü uygularsa kullanılabilir. Örnek: @AppStorage("theme") var theme: AppTheme = .system. SwiftUI, enum'ı rawValue aracılığıyla otomatik olarak serileştirir ve yüklemede geri yükler.
Standart depolama için UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!) veya belirli bir anahtar için removeObject(forKey:) işlevini çağırın. Temizlemeden sonra, tüm @AppStorage özellikleri bildirimde belirtilen varsayılan değerlere dönecektir.
Evet, uygulama ve uzantılar arasında senkronizasyon için App Group kullanın: @AppStorage("key", store: UserDefaults(suiteName: "group.com.example.app")!). Widget, Share Extension ve Watch App aynı UserDefaults'ı okuyup yazabilir ve değişiklikler otomatik olarak izlenir.
@AppStorage, küçük miktarlardaki veriler (ayarlar, tokenler, sayaçlar) için tasarlanmış UserDefaults'ı kullanır. Önerilen sınır uygulama başına 100 KB'a kadardır. Yapılandırılmış veya büyük veriler (nesne dizileri, medya dosyaları) için SwiftData, Core Data veya dosya sistemini kullanın.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun