NSUserDefaults je úložiště dat klíč-hodnota v iOS, watchOS, tvOS a macOS, určené pro ukládání nastavení a konfigurací aplikace. Data jsou uložena v souboru plist v sandboxu aplikace a automaticky synchronizována s iCloud přes NSUbiquitousKeyValueStore. Podle oficiální dokumentace Apple Developer, 2025, NSUserDefaults podporuje ukládání primitivních typů: String, Int, Bool, Float, Double, Data, Date, Array a Dictionary. Třída byla přejmenována na UserDefaults od Swift 3, ale její Objective-C název NSUserDefaults zůstává široce používán v kódové bázi a dokumentaci Apple.
Hlavní body
NSUserDefaults (UserDefaults ve Swift) je vestavěný mechanismus Apple pro ukládání párů klíč-hodnota ve formátu plist. Je dostupný na všech platformách Apple: iOS, iPadOS, watchOS, tvOS a macOS. Hlavní účel — ukládání uživatelských preferencí, stavu rozhraní, příznaků prvního spuštění, vybraných možností a dalších jednoduchých dat, která přežijí restart aplikace.
Každá aplikace pro iOS má izolovaný sandbox a NSUserDefaults je uložen v adresáři Library/Preferences uvnitř tohoto sandboxu v souboru s názvem Bundle Identifier. Soubor plist obsahuje páry klíč-hodnota, kde klíčem je řetězec a hodnotou je jeden z podporovaných typů. Velikost souboru není omezena, ale Apple doporučuje ukládat do UserDefaults pouze nastavení, ne velké objemy dat.
Od iOS 8, NSUserDefaults podporuje App Groups — sdílené úložiště mezi aplikacemi stejného vývojáře a jejich rozšířeními (widgety, watchOS doprovodné aplikace). K tomu se používá inicializátor init?(suiteName:) s identifikátorem App Group. To umožňuje například widgetu na obrazovce Today číst nastavení z hlavní aplikace bez duplikování logiky ukládání.
Fyzicky je NSUserDefaults uložen v binárním souboru plist na cestě: {Sandbox}/Library/Preferences/com.example.myapp.plist. Soubor používá binární formát plist (NSPropertyListBinaryFormat_v1_0) pro kompaktnost a rychlost čtení. Na macOS může být soubor ve formátu XML pro kompatibilitu. Na rozdíl od SharedPreferences na Androidu, plist soubory UserDefaults mohou obsahovat vnořené struktury pomocí Dictionary a Array.
Soubory NSUserDefaults nejsou ve výchozím nastavení šifrovány. Data jsou uložena v otevřené podobě a lze je číst při fyzickém přístupu k zařízení nebo přes zálohu. Pro ukládání citlivých dat (hesla, tokeny, šifrovací klíče) Apple důrazně doporučuje používat Keychain, který automaticky šifruje data na úrovni operačního systému.
NSUserDefaults funguje na principu cache v paměti s periodickou synchronizací na disk. Při prvním přístupu ke standardní instanci UserDefaults.standard systém načte soubor plist do RAM ve formě Dictionary. Všechna následná čtení se provádějí z paměti. Zápis se také nejprve provádí do paměti a synchronizace na disk probíhá periodicky na pozadí.
Operace zápisu používají metodu set(_:forKey:), která přijímá volitelnou hodnotu typu Any?. Hodnota může být nil — pro odstranění klíče. Pro okamžitý zápis na disk se dříve používala metoda synchronize(), ale od iOS 7 a OS X 10.9 již není nutná — systém automaticky synchronizuje data v pravidelných intervalech. Apple oficiálně prohlásil synchronize() za nadbytečnou ve své dokumentaci.
NSUserDefaults používá systém registrů (domén) pro organizaci vyhledávání hodnot. Když aplikace požaduje hodnotu podle klíče, UserDefaults postupně kontroluje domény v určitém pořadí: nejprve NSArgumentDomain (argumenty příkazového řádku), poté doménu aplikace (Application), poté NSGlobalDomain (systémová nastavení), poté jazykově specifické domény a nakonec NSRegistrationDomain (výchozí hodnoty registrované přes register(defaults:)).
import Foundation
// Standardní instance UserDefaults
let defaults = UserDefaults.standard
// Zápis hodnot
defaults.set("Anna Petrová", forKey: "username")
defaults.set(28, forKey: "age")
defaults.set(true, forKey: "isLoggedIn")
// Registrace výchozích hodnot
defaults.register(defaults: [
"theme": "system",
"fontSize": 14
])
// Čtení s vrácením výchozí hodnoty
let theme = defaults.string(forKey: "theme") ?? "system"
let fontSize = defaults.integer(forKey: "fontSize")
Doména NSRegistrationDomain je softwarová doména, která existuje pouze v RAM a není ukládána na disk. Používá se pro nastavení výchozích hodnot, které jsou aktivní, dokud aplikace nezapíše svou vlastní hodnotu do domény aplikace. To umožňuje vytvořit jednotný konfigurační bod pro výchozí nastavení, která lze centrálně měnit ve fázi vývoje.
NSUserDefaults poskytuje sadu typových metod pro čtení a zápis dat: string(forKey:), integer(forKey:), bool(forKey:), float(forKey:), double(forKey:), data(forKey:), array(forKey:), dictionary(forKey:) a object(forKey:). Každá metoda čtení má odpovídající metodu zápisu set(_:forKey:) s automatickým určením typu ukládané hodnoty. Swift verze UserDefaults používá striktní typování, ale Objective-C verze přijímá a vrací id.
| Metoda čtení (Swift) | Datový typ | Výchozí hodnota |
|---|---|---|
| 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 |
Metoda synchronize() v NSUserDefaults vynutí zápis všech změn z paměti na disk. V raných verzích iOS bylo nutné tuto metodu volat po každém zápisu pro zaručení uložení dat. Od iOS 7 systém automaticky synchronizuje UserDefaults na pozadí a Apple oficiálně prohlásil synchronize() za nadbytečnou. Volání této metody nezpůsobí chybu, ale neposkytuje žádné dodatečné záruky uložení.
Pro sledování změn poskytuje NSUserDefaults oznámení UserDefaults.didChangeNotification a metodu KVO pozorování addObserver(_:forKeyPath:options:context:). Ve SwiftUI je k dispozici Property Wrapper @AppStorage, který automaticky synchronizuje hodnotu v UserDefaults s aktualizací UI. @AppStorage podporuje stejné typy jako UserDefaults a je preferovaným způsobem práce s nastaveními ve SwiftUI aplikacích.
// Sledování změn přes KVO
class SettingsViewModel: NSObject {
override func observeValue(
forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey: Any]?,
context: UnsafeMutableRawPointer?
) {
guard let keyPath else { return }
print("Klíč se změnil: \(keyPath)")
}
}
// SwiftUI - AppStorage
struct SettingsView: View {
@AppStorage("theme") private var theme: String = "system"
var body: some View {
Picker("Téma", selection: $theme) {
Text("Systémové").tag("system")
Text("Světlé").tag("light")
Text("Tmavé").tag("dark")
}
}
}
Pro práci s App Groups (sdílené úložiště mezi aplikací a rozšířeními) se používá inicializátor UserDefaults(suiteName:) s identifikátorem App Group. Například "group.com.example.myapp". Data zapsaná do této instance jsou přístupná z hlavní aplikace, widgetu, watchOS doprovodné aplikace a dalších rozšíření patřících do stejné App Group. Každá instance suite je uložena v samostatném souboru plist.
Navzdory pohodlí a jednoduchosti není NSUserDefaults univerzálním úložištěm pro všechny typy dat na iOS. V závislosti na objemu, kritičnosti a bezpečnostních požadavcích Apple poskytuje několik alternativ, z nichž každá je optimalizována pro konkrétní scénář použití.
| Řešení | Kdy použít | Omezení |
|---|---|---|
| NSUserDefaults | Nastavení rozhraní a konfigurace | Není vhodné pro velká data a tajemství |
| Keychain | Hesla, tokeny, šifrovací klíče | Složitější na použití, pomalejší |
| CoreData | Strukturovaná data se vztahy | Příliš rozsáhlé pro 10-20 nastavení |
| FileManager | Dokumenty, obrázky, binární data | Vyžaduje ruční správu souborů |
| CloudKit | Cloudová synchronizace mezi zařízeními | Vyžaduje účet iCloud a síťové připojení |
Keychain je chráněné úložiště Apple pro důvěrná data. Na rozdíl od NSUserDefaults jsou všechna data v Keychain šifrována na úrovni operačního systému pomocí hardwarového šifrování Secure Enclave na kompatibilních zařízeních. Keychain se automaticky zamyká a odemyká spolu se zařízením a podporuje sdílení přístupu mezi aplikacemi stejného vývojáře prostřednictvím Keychain Access Groups.
Hlavní nevýhodou Keychain je složitost API. Pro jednoduché uložení řetězce je třeba vytvořit požadavek SecItemAdd s uvedením atributů: třída (kSecClassGenericPassword), služba (kSecAttrService), účet (kSecAttrAccount) a samotná data (kSecValueData). Pro zjednodušení práce s Keychain existují obaly třetích stran, jako jsou KeychainAccess a SwiftKeychainWrapper, které poskytují pohodlné rozhraní klíč-hodnota podobné UserDefaults.
Podívejme se na praktický příklad: ukládání a obnovení stavu onboardingu (uvítacích obrazovek) v aplikaci pro iOS pomocí NSUserDefaults. Při prvním spuštění uživatel vidí uvítací obrazovky, po jejichž absolvování se příznak uloží do UserDefaults. Při dalších spuštěních se onboarding přeskočí. Pro SwiftUI se používá @AppStorage, pro UIKit — přímý přístup k UserDefaults.standard.
Vytvořme správce OnboardingManager, který zapouzdřuje práci s UserDefaults pro ukládání stavu onboardingu. Správce poskytuje vlastnost isOnboardingCompleted pro kontrolu stavu a metodu markOnboardingCompleted pro nastavení příznaku. Klíč pro ukládání je vyjmut do konstanty pro zabránění překlepům. Pro unit testování správce používá protokol UserDefaultsProtocol, který umožňuje nahradit skutečné úložiště za MockUserDefaults.
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)
}
}
// Použití v aplikaci
let onboardingManager = OnboardingManager()
if !onboardingManager.isOnboardingCompleted {
showOnboarding()
} else {
showMainScreen()
}
Pro ukládání složitějších nastavení, jako je strukturovaný objekt Profile, se doporučuje použití protokolu Codable a JSONEncoder/JSONDecoder. Objekt je serializován do Data přes JSONEncoder, uložen přes set(_:forKey:), a při čtení deserializován z Data zpět do objektu přes JSONDecoder. Tento přístup umožňuje ukládat složité struktury v UserDefaults bez ztráty typové bezpečnosti.
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)
}
}
// Použití
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")
Je důležité si pamatovat, že NSUserDefaults není určen pro ukládání velkých objemů dat. Apple doporučuje omezit velikost ukládaných dat na několik desítek kilobajtů. Pro ukládání velkých objektů (obrázky, dokumenty, serializované modely) byste měli použít FileManager s adresářem Documents nebo CoreData. Kromě toho UserDefaults nepodporuje verzování datového schématu — při změně struktury Codable modelu se stará data nemusí deserializovat a to je třeba ošetřit v kódu aplikace.
Často kladené otázky
Oba jsou úložiště klíč-hodnota, ale NSUserDefaults podporuje více typů (Data, Date, Array, Dictionary) a automaticky se synchronizuje s iCloud. SharedPreferences ukládá data v XML, NSUserDefaults — ve formátu plist. NSUserDefaults má systém domén s kaskádovým vyhledáváním, SharedPreferences používá jednoduchou plochou strukturu s názvy souborů.
Ne, NSUserDefaults ukládá data v otevřené podobě bez šifrování. Pro hesla, tokeny a šifrovací klíče používejte Keychain, který šifruje data na úrovni Secure Enclave. Keychain také podporuje atributy přístupu, jako je biometrická autentizace (Face ID / Touch ID) před čtením tajemství.
Pro synchronizaci mezi zařízeními stejného uživatele použijte NSUbiquitousKeyValueStore — cloudové úložiště klíč-hodnota iCloud. Data zapsaná do této služby na jednom zařízení se automaticky objeví na všech ostatních zařízeních stejného účtu iCloud. Maximální objem — 1 MB na aplikaci, 1024 klíčů.
Pro odstranění všech dat zavolejte metodu removePersistentDomain(forName:) s Bundle Identifier aplikace. Pro odstranění jednotlivých hodnot použijte removeObject(forKey:). Pro úplný reset nastavení aplikace: UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!). Všechna odstranění se okamžitě projeví v paměťové cache.
Apple nestanovuje striktní limit pro velikost NSUserDefaults, ale doporučuje se nepřekračovat 100 KB pro celkový objem všech uložených dat. Pro velké objemy použijte CoreData nebo FileManager. Při ukládání více než 1 MB dat může být výkon čtení při spuštění aplikace znatelně snížen.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také