NSUserDefaults, iOS, watchOS, tvOS ve macOS'te uygulama ayarlarını ve yapılandırmalarını kaydetmek için tasarlanmış bir anahtar-değer veri deposudur. Veriler, uygulama sanal alanındaki bir plist dosyasında saklanır ve NSUbiquitousKeyValueStore aracılığıyla otomatik olarak iCloud ile senkronize edilir. Resmi belgelere göre Apple Developer, 2025, NSUserDefaults ilkel türlerin saklanmasını destekler: String, Int, Bool, Float, Double, Data, Date, Array ve Dictionary. Swift 3'ten itibaren sınıfın adı UserDefaults olarak değiştirildi, ancak Objective-C adı NSUserDefaults, kod tabanlarında ve Apple belgelerinde yaygın olarak kullanılmaya devam etmektedir.
Önemli Noktalar
NSUserDefaults (Swift'te UserDefaults), plist formatında anahtar-değer çiftlerini saklamak için Apple'ın yerleşik mekanizmasıdır. Tüm Apple platformlarında mevcuttur: iOS, iPadOS, watchOS, tvOS ve macOS. Temel amacı, kullanıcı tercihlerini, arayüz durumunu, ilk açılış işaretlerini, seçili seçenekleri ve uygulama yeniden başlatmalarında kalıcı olan diğer basit verileri kaydetmektir.
Her iOS uygulamasının izole bir sanal alanı vardır ve NSUserDefaults bu sanal alan içindeki Library/Preferences dizininde Bundle Identifier adlı bir dosyada saklanır. Plist dosyası, anahtarın bir dize ve değerin desteklenen türlerden biri olduğu anahtar-değer çiftlerini içerir. Dosya boyutu sınırlı değildir, ancak Apple UserDefaults'ta yalnızca ayarların saklanmasını, büyük miktarda veri saklanmamasını önerir.
iOS 8'den itibaren NSUserDefaults, App Groups'u desteklemeye başladı — aynı geliştiricinin uygulamaları ve bunların uzantıları (widget'lar, watchOS yardımcı uygulamaları) arasında paylaşımlı depolama. Bunun için bir App Group tanımlayıcısıyla init?(suiteName:) başlatıcısı kullanılır. Bu, örneğin bir Today widget'ının kaydetme mantığını kopyalamadan ana uygulamadan ayarları okumasına olanak tanır.
Fiziksel olarak, NSUserDefaults şu yolda bir ikili plist dosyasında saklanır: {Sandbox}/Library/Preferences/com.example.myapp.plist. Dosya, kompaktlık ve okuma hızı için ikili plist formatını (NSPropertyListBinaryFormat_v1_0) kullanır. macOS'ta dosya, uyumluluk için XML formatında olabilir. Android'deki SharedPreferences'ın aksine, UserDefaults'ın plist dosyaları Dictionary ve Array aracılığıyla iç içe yapılar içerebilir.
NSUserDefaults dosyaları varsayılan olarak şifrelenmez. Veriler düz metin olarak saklanır ve cihaza fiziksel erişim veya yedekleme yoluyla okunabilir. Hassas verileri (şifreler, token'lar, şifreleme anahtarları) saklamak için Apple, işletim sistemi düzeyinde verileri otomatik olarak şifreleyen Keychain kullanılmasını şiddetle önerir.
NSUserDefaults, periyodik disk senkronizasyonuyla bellek önbellekleme prensibine göre çalışır. Standart UserDefaults.standard örneğine ilk erişimde sistem, plist dosyasını Dictionary olarak RAM'e yükler. Sonraki tüm okumalar bellekten gerçekleştirilir. Yazma da önce bellekte gerçekleşir ve disk senkronizasyonu periyodik olarak bir arka plan iş parçacığında gerçekleşir.
Yazma işlemleri, isteğe bağlı Any? türünde bir değer kabul eden set(_:forKey:) yöntemini kullanır. Değer nil olabilir — bir anahtarı kaldırmak için kullanılır. Anlık disk yazma için daha önce synchronize() yöntemi kullanılıyordu, ancak iOS 7 ve OS X 10.9'dan itibaren artık gerekli değildir — sistem verileri düzenli aralıklarla otomatik olarak senkronize eder. Apple, belgelerinde synchronize() işlevini gereksiz olarak resmen ilan etti.
NSUserDefaults, değer aramasını düzenlemek için bir kayıt (etki alanı) sistemi kullanır. Bir uygulama bir anahtarla değer istediğinde, UserDefaults belirli bir sırayla etki alanlarını sırayla kontrol eder: önce NSArgumentDomain (komut satırı argümanları), sonra Uygulama etki alanı, sonra NSGlobalDomain (sistem ayarları), sonra dile özgü etki alanları ve son olarak NSRegistrationDomain (register(defaults:) aracılığıyla kaydedilen varsayılan değerler).
import Foundation
// UserDefaults standart örneği
let defaults = UserDefaults.standard
// Değer yazma
defaults.set("Anna Petrova", forKey: "username")
defaults.set(28, forKey: "age")
defaults.set(true, forKey: "isLoggedIn")
// Varsayılan değerleri kaydetme
defaults.register(defaults: [
"theme": "system",
"fontSize": 14
])
// Varsayılan değer dönüşüyle okuma
let theme = defaults.string(forKey: "theme") ?? "system"
let fontSize = defaults.integer(forKey: "fontSize")
NSRegistrationDomain, yalnızca bellekte bulunan ve diske kaydedilmeyen programatik bir etki alanıdır. Uygulama, Uygulama etki alanına kendi değerini yazana kadar geçerli olan varsayılan değerleri ayarlamak için kullanılır. Bu, geliştirme sırasında merkezi olarak değiştirilebilen varsayılan ayarlar için tek bir yapılandırma noktası oluşturulmasına olanak tanır.
NSUserDefaults veri okuma ve yazma için bir dizi tür belirtilmiş yöntem sağlar: string(forKey:), integer(forKey:), bool(forKey:), float(forKey:), double(forKey:), data(forKey:), array(forKey:), dictionary(forKey:) ve object(forKey:). Her okuma yönteminin, saklanan değerin otomatik tür belirlemesiyle birlikte karşılık gelen bir set(_:forKey:) yazma yöntemi vardır. UserDefaults'ın Swift sürümü güçlü tür kullanırken, Objective-C sürümü id kabul eder ve döndürür.
| Okuma Yöntemi (Swift) | Veri Türü | Varsayılan Değer |
|---|---|---|
| string(forKey:) | String? | nil |
| integer(forKey:) | Int | 0 |
| bool(forKey:) | Bool | false |
| float(forKey:) | Float | 0.0 |
| double(forKey:) | Double | 0.0 |
| data(forKey:) | Data? | nil |
NSUserDefaults'taki synchronize() yöntemi, tüm değişiklikleri bellekten diske zorla yazar. iOS'un ilk sürümlerinde, veri kalıcılığını sağlamak için her yazma işleminden sonra bu yöntemin çağrılması gerekiyordu. iOS 7'den itibaren sistem, arka plan iş parçacığında UserDefaults'ı otomatik olarak senkronize eder ve Apple, synchronize() işlevini resmen gereksiz ilan etti. Bu yöntemi çağırmak bir hataya neden olmaz ancak ek kalıcılık garantisi sağlamaz.
Değişiklikleri izlemek için NSUserDefaults, UserDefaults.didChangeNotification bildirimini ve KVO gözlem yöntemi addObserver(_:forKeyPath:options:context:) sağlar. SwiftUI'de, UserDefaults'taki bir değeri UI güncellemeleriyle otomatik olarak senkronize eden @AppStorage Property Wrapper mevcuttur. @AppStorage, UserDefaults ile aynı türleri destekler ve SwiftUI uygulamalarında ayarlarla çalışmanın tercih edilen yoludur.
// KVO ile değişiklikleri izleme
class SettingsViewModel: NSObject {
override func observeValue(
forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey: Any]?,
context: UnsafeMutableRawPointer?
) {
guard let keyPath else { return }
print("Anahtar değişti: \(keyPath)")
}
}
// SwiftUI - AppStorage
struct SettingsView: View {
@AppStorage("theme") private var theme: String = "system"
var body: some View {
Picker("Tema", selection: $theme) {
Text("Sistem").tag("system")
Text("Açık").tag("light")
Text("Koyu").tag("dark")
}
}
}
App Groups (bir uygulama ve uzantıları arasında paylaşımlı depolama) ile çalışmak için bir App Group tanımlayıcısıyla UserDefaults(suiteName:) başlatıcısını kullanın. Örneğin, “group.com.example.myapp”. Bu örneğe yazılan veriler, ana uygulama, widget, watchOS yardımcı uygulaması ve aynı App Group'a ait diğer uzantılardan erişilebilir. Her suite örneği ayrı bir plist dosyasında saklanır.
Kolaylığına ve basitliğine rağmen NSUserDefaults, iOS'taki tüm veri türleri için evrensel bir depolama çözümü değildir. Hacim, kritiklik ve güvenlik gereksinimlerine bağlı olarak Apple, her biri belirli bir kullanım durumu için optimize edilmiş birkaç alternatif sunar.
| Çözüm | Ne Zaman Kullanılmalı | Sınırlamalar |
|---|---|---|
| NSUserDefaults | Arayüz ayarları ve yapılandırma | Büyük veriler veya sırlar için uygun değil |
| Keychain | Şifreler, token'lar, şifreleme anahtarları | Kullanımı daha karmaşık, daha yavaş |
| CoreData | İlişkilerle yapılandırılmış veri | 10–20 ayar için aşırı |
| FileManager | Belgeler, görseller, ikili veri | Manuel dosya yönetimi gerektirir |
| CloudKit | Cihazlar arasında bulut senkronizasyonu | iCloud hesabı ve ağ bağlantısı gerektirir |
Keychain, gizli veriler için Apple'ın güvenli deposudur. NSUserDefaults'ın aksine, Keychain'deki tüm veriler, uyumlu cihazlarda Secure Enclave'den donanım şifrelemesi kullanılarak işletim sistemi düzeyinde şifrelenir. Keychain, cihazla birlikte otomatik olarak kilitlenir ve açılır ve Keychain Access Groups aracılığıyla aynı geliştiricinin uygulamaları arasında erişim paylaşımını destekler.
Keychain'in ana dezavantajı API karmaşıklığıdır. Basit bir dize kaydetmek için bile şu öznitelikleri belirterek bir SecItemAdd sorgusu oluşturmanız gerekir: sınıf (kSecClassGenericPassword), hizmet (kSecAttrService), hesap (kSecAttrAccount) ve gerçek veriler (kSecValueData). Keychain ile çalışmayı basitleştirmek için, UserDefaults'a benzer kullanışlı bir anahtar-değer arayüzü sağlayan KeychainAccess ve SwiftKeychainWrapper gibi üçüncü taraf sarmalayıcılar mevcuttur.
Pratik bir örnek düşünelim: NSUserDefaults kullanarak bir iOS uygulamasında karşılama (onboarding) durumunu kaydetme ve geri yükleme. İlk açılışta kullanıcı karşılama ekranlarını görür; bunları tamamladıktan sonra UserDefaults'ta bir işaret kaydedilir. Sonraki açılışlarda karşılama atlanır. SwiftUI için @AppStorage kullanılır; UIKit için UserDefaults.standard'a doğrudan erişim.
Karşılama durumunu saklamak için UserDefaults ile çalışmayı kapsülleyen bir OnboardingManager oluşturalım. Yönetici, durumu kontrol etmek için isOnboardingCompleted özelliği ve işareti ayarlamak için markOnboardingCompleted yöntemi sağlar. Depolama anahtarı, yazım hatalarını önlemek için bir sabite çıkarılır. Birim testleri için yönetici, gerçek depolamanın MockUserDefaults ile değiştirilmesine olanak tanıyan bir UserDefaultsProtocol kullanır.
class OnboardingManager {
private let defaults: UserDefaults
private let hasSeenKey = "has_seen_onboarding"
init(defaults: UserDefaults = .standard) {
self.defaults = defaults
}
var isOnboardingCompleted: Bool {
defaults.bool(forKey: hasSeenKey)
}
func markOnboardingCompleted() {
defaults.set(true, forKey: hasSeenKey)
}
func resetOnboarding() {
defaults.removeObject(forKey: hasSeenKey)
}
}
// Uygulamada kullanım
let onboardingManager = OnboardingManager()
if !onboardingManager.isOnboardingCompleted {
showOnboarding()
} else {
showMainScreen()
}
Yapılandırılmış bir Profile nesnesi gibi daha karmaşık ayarları saklamak için Codable protokolü ve JSONEncoder/JSONDecoder kullanılması önerilir. Nesne, JSONEncoder aracılığıyla Data'ya serileştirilir, set(_:forKey:) ile kaydedilir ve okurken JSONDecoder aracılığıyla Data'dan nesneye geri dönüştürülür. Bu yaklaşım, tür güvenliğini kaybetmeden UserDefaults'ta karmaşık yapıların saklanmasına olanak tanır.
struct UserProfile: Codable {
let name: String
let age: Int
let preferences: [String: String]
}
extension UserDefaults {
func save<T: Codable>(_ value: T, forKey key: String) {
if let data = try? JSONEncoder().encode(value) {
set(data, forKey: key)
}
}
func load<T: Codable>(_ type: T.Type, forKey key: String) -> T? {
guard let data = data(forKey: key) else { return nil }
return try? JSONDecoder().decode(type, from: data)
}
}
// Kullanım
let profile = UserProfile(name: "Anna", age: 28, preferences: ["theme": "dark"])
UserDefaults.standard.save(profile, forKey: "user_profile")
let loaded = UserDefaults.standard.load(UserProfile.self, forKey: "user_profile")
NSUserDefaults'un büyük miktarlarda veri depolamak için tasarlanmadığını unutmamak önemlidir. Apple, saklanan verilerin birkaç on kilobaytla sınırlandırılmasını önerir. Büyük nesneleri (görseller, belgeler, serileştirilmiş modeller) saklamak için Documents diziniyle FileManager veya CoreData kullanın. Ayrıca UserDefaults, veri şeması sürümlemeyi desteklemez — Codable model yapısı değiştiğinde eski veriler serileştirme dışı kalabilir ve bu uygulama kodunda ele alınmalıdır.
Sıkça Sorulan Sorular
Her ikisi de anahtar-değer depolarıdır, ancak NSUserDefaults daha fazla türü (Data, Date, Array, Dictionary) destekler ve otomatik olarak iCloud ile senkronize olur. SharedPreferences verileri XML'de saklarken, NSUserDefaults plist formatında saklar. NSUserDefaults basamaklı aramalı bir etki alanı sistemine sahipken, SharedPreferences dosya adlarıyla basit bir düz yapı kullanır.
Hayır, NSUserDefaults verileri şifreleme olmadan düz metin olarak saklar. Şifreler, token'lar ve şifreleme anahtarları için Secure Enclave düzeyinde verileri şifreleyen Keychain kullanın. Keychain ayrıca bir sırrı okumadan önce biyometrik kimlik doğrulama (Face ID / Touch ID) gibi erişim özniteliklerini de destekler.
Aynı kullanıcının cihazları arasında senkronizasyon için NSUbiquitousKeyValueStore — iCloud bulut anahtar-değer deposunu kullanın. Bir cihazda bu hizmete yazılan veriler, aynı iCloud hesabına sahip diğer tüm cihazlarda otomatik olarak görünür. Maksimum kapasite: uygulama başına 1 MB, 1024 anahtar.
Tüm verileri silmek için uygulamanın Bundle Identifier'ı ile removePersistentDomain(forName:) yöntemini çağırın. Tek tek değerleri kaldırmak için removeObject(forKey:) kullanın. Tam ayar sıfırlama için: UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!). Tüm silmeler anında bellek önbelleğine uygulanır.
Apple, NSUserDefaults boyutu için katı bir sınır belirlemez, ancak saklanan tüm verilerin toplam hacminin 100 KB'ı aşmaması önerilir. Daha büyük hacimler için CoreData veya FileManager kullanın. 1 MB'ın üzerinde veri saklandığında, uygulama başlatılırken okuma performansı belirgin şekilde düşebilir.
Ö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