NSUserDefaults är en nyckel-värde datalagring i iOS, watchOS, tvOS och macOS, avsedd för att spara appens inställningar och konfigurationer. Data lagras i en plist-fil i appens sandlåda och synkroniseras automatiskt med iCloud via NSUbiquitousKeyValueStore. Enligt officiell dokumentation Apple Developer, 2025, stöder NSUserDefaults lagring av primitiva typer: String, Int, Bool, Float, Double, Data, Date, Array och Dictionary. Klassen har bytt namn till UserDefaults från och med Swift 3, men dess Objective-C-namn NSUserDefaults förblir allmänt använt i kodbasen och Apples dokumentation.
Huvudpunkter
NSUserDefaults (UserDefaults i Swift) är en inbyggd Apple-mekanism för att lagra nyckel-värde-par i plist-format. Den är tillgänglig på alla Apple-plattformar: iOS, iPadOS, watchOS, tvOS och macOS. Huvudsyftet är att spara användarpreferenser, gränssnittstillstånd, första-start-flaggor, valda alternativ och andra enkla data som överlever en omstart av appen.
Varje iOS-app har en isolerad sandlåda och NSUserDefaults lagras i katalogen Library/Preferences i denna sandlåda i en fil med namnet Bundle Identifier. Plist-filen innehåller nyckel-värde-par, där nyckeln är en sträng och värdet är en av de typer som stöds. Filstorleken är inte begränsad, men Apple rekommenderar att endast inställningar lagras i UserDefaults, inte stora datamängder.
Från och med iOS 8 stöder NSUserDefaults App Groups — delad lagring mellan appar från samma utvecklare och deras tillägg (widgetar, watchOS medföljande appar). För detta används initialiseraren init?(suiteName:) med App Group-identifieraren. Detta gör det möjligt för en widget på Today-skärmen att läsa inställningar från huvudappen utan att duplicera lagringslogik.
Fysiskt lagras NSUserDefaults i en binär plist-fil på sökvägen: {Sandbox}/Library/Preferences/com.example.myapp.plist. Filen använder binärt plist-format (NSPropertyListBinaryFormat_v1_0) för kompakthet och läshastighet. På macOS kan filen vara i XML-format för kompatibilitet. Till skillnad från SharedPreferences på Android kan UserDefaults plist-filer innehålla nästlade strukturer via Dictionary och Array.
NSUserDefaults-filer är inte krypterade som standard. Data lagras i öppen form och kan läsas vid fysisk åtkomst till enheten eller via säkerhetskopia. För lagring av känslig data (lösenord, tokens, krypteringsnycklar) rekommenderar Apple starkt att använda Keychain, som automatiskt krypterar data på operativsystemsnivå.
NSUserDefaults fungerar enligt principen om cachning i minnet med periodisk synkronisering till disk. Vid första åtkomst till standardinstansen UserDefaults.standard laddar systemet plist-filen i RAM-minnet som en Dictionary. Alla efterföljande läsningar görs från minnet. Skrivning sker också först i minnet, och synkronisering till disk sker periodiskt i bakgrunden.
Skrivoperationer använder metoden set(_:forKey:), som tar ett valfritt värde av typen Any?. Värdet kan vara nil — för att ta bort en nyckel. För omedelbar skrivning till disk användes tidigare metoden synchronize(), men från och med iOS 7 och OS X 10.9 krävs den inte längre — systemet synkroniserar automatiskt data med jämna mellanrum. Apple har officiellt förklarat synchronize() överflödig i sin dokumentation.
NSUserDefaults använder ett system av register (domäner) för att organisera sökning efter värden. När appen begär ett värde baserat på en nyckel kontrollerar UserDefaults successivt domänerna i en viss ordning: först NSArgumentDomain (kommandoradsargument), sedan applikationsdomänen (Application), sedan NSGlobalDomain (systeminställningar), sedan språkspecifika domäner och slutligen NSRegistrationDomain (standardvärden registrerade via register(defaults:)).
import Foundation
// Standard UserDefaults-instans
let defaults = UserDefaults.standard
// Skriva värden
defaults.set("Anna Petrova", forKey: "username")
defaults.set(28, forKey: "age")
defaults.set(true, forKey: "isLoggedIn")
// Registrering av standardvärden
defaults.register(defaults: [
"theme": "system",
"fontSize": 14
])
// Läsa med returnering av standardvärde
let theme = defaults.string(forKey: "theme") ?? "system"
let fontSize = defaults.integer(forKey: "fontSize")
Domänen NSRegistrationDomain är en programdomän som endast finns i RAM-minnet och inte sparas på disken. Den används för att ställa in standardvärden som är aktiva tills appen skriver sitt eget värde i applikationsdomänen. Detta gör det möjligt att skapa en enda konfigurationspunkt för standardinställningar som kan ändras centralt under utvecklingsfasen.
NSUserDefaults tillhandahåller en uppsättning typade metoder för att läsa och skriva data: string(forKey:), integer(forKey:), bool(forKey:), float(forKey:), double(forKey:), data(forKey:), array(forKey:), dictionary(forKey:) och object(forKey:). Varje läshar metod har en motsvarande skrivmetod set(_:forKey:) med automatisk bestämning av typen för det lagrade värdet. Swift-versionen av UserDefaults använder strikt typning, men Objective-C-versionen accepterar och returnerar id.
| Läsmetod (Swift) | Datatyp | Standardvärde |
|---|---|---|
| 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 |
Metoden synchronize() i NSUserDefaults tvingar fram skrivning av alla ändringar från minnet till disken. I tidiga versioner av iOS var denna metod tvungen att anropas efter varje skrivning för att garantera datalagring. Från och med iOS 7 synkroniserar systemet automatiskt UserDefaults i bakgrunden, och Apple har officiellt förklarat synchronize() överflödig. Anrop av denna metod orsakar inte ett fel, men ger inga ytterligare garantier för lagring.
För att övervaka ändringar tillhandahåller NSUserDefaults notifikationen UserDefaults.didChangeNotification och KVO-observationsmetoden addObserver(_:forKeyPath:options:context:). I SwiftUI finns Property Wrapper @AppStorage, som automatiskt synkroniserar värdet i UserDefaults med UI-uppdateringar. @AppStorage stöder samma typer som UserDefaults och är det föredragna sättet att arbeta med inställningar i SwiftUI-appar.
// Observera ändringar via KVO
class SettingsViewModel: NSObject {
override func observeValue(
forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey: Any]?,
context: UnsafeMutableRawPointer?
) {
guard let keyPath else { return }
print("Nyckel ändrad: \(keyPath)")
}
}
// SwiftUI - AppStorage
struct SettingsView: View {
@AppStorage("theme") private var theme: String = "system"
var body: some View {
Picker("Tema", selection: $theme) {
Text("System").tag("system")
Text("Ljus").tag("light")
Text("Mörk").tag("dark")
}
}
}
För arbete med App Groups (delad lagring mellan app och tillägg) används initialiseraren UserDefaults(suiteName:) med App Group-identifieraren. Till exempel, "group.com.example.myapp". Data som skrivs till denna instans är tillgänglig från huvudappen, widgeten, watchOS-medföljande appen och andra tillägg som tillhör samma App Group. Varje suite-instans lagras i en separat plist-fil.
Trots bekvämligheten och enkelheten är NSUserDefaults inte en universell lagring för alla datatyper på iOS. Beroende på volym, kritikalitet och säkerhetskrav tillhandahåller Apple flera alternativ, var och en optimerad för ett specifikt användningsscenario.
| Lösning | När ska användas | Begränsningar |
|---|---|---|
| NSUserDefaults | Gränssnittsinställningar och konfiguration | Inte lämpligt för stora data och hemligheter |
| Keychain | Lösenord, tokens, krypteringsnycklar | Mer komplicerat att använda, långsammare |
| CoreData | Strukturerad data med relationer | Överdrivet för 10-20 inställningar |
| FileManager | Dokument, bilder, binär data | Kräver manuell filhantering |
| CloudKit | Molnsynkronisering mellan enheter | Kräver iCloud-konto och nätverksanslutning |
Keychain är en skyddad Apple-lagring för konfidentiell data. Till skillnad från NSUserDefaults krypteras all data i Keychain på operativsystemsnivå med hjälp av Secure Enclave-hårdvarukryptering på kompatibla enheter. Keychain låses och låses upp automatiskt tillsammans med enheten och stöder delning av åtkomst mellan appar från samma utvecklare via Keychain Access Groups.
Den största nackdelen med Keychain är API:ets komplexitet. För att enkelt lagra en sträng måste en SecItemAdd-förfrågan skapas med angivande av attribut: klass (kSecClassGenericPassword), tjänst (kSecAttrService), konto (kSecAttrAccount) och själva data (kSecValueData). För att förenkla arbetet med Keychain finns tredjepartsomslag som KeychainAccess och SwiftKeychainWrapper, som ger ett bekvämt nyckel-värde-gränssnitt liknande UserDefaults.
Låt oss titta på ett praktiskt exempel: spara och återställa onboarding-status (välkomstskärmar) i en iOS-app med NSUserDefaults. Vid första start ser användaren onboarding-skärmarna, efter att ha gått igenom dem sparas en flagga i UserDefaults. Vid efterföljande starter hoppas onboarding över. För SwiftUI används @AppStorage, för UIKit — direkt åtkomst till UserDefaults.standard.
Låt oss skapa en hanterare OnboardingManager som kapslar in arbetet med UserDefaults för att lagra onboarding-status. Hanteraren tillhandahåller egenskapen isOnboardingCompleted för att kontrollera status och metoden markOnboardingCompleted för att ställa in flaggan. Lagringsnyckeln har placerats i en konstant för att förhindra stavfel. För enhetstestning använder hanteraren protokollet UserDefaultsProtocol, vilket gör det möjligt att ersätta den verkliga lagringen med 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)
}
}
// Användning i appen
let onboardingManager = OnboardingManager()
if !onboardingManager.isOnboardingCompleted {
showOnboarding()
} else {
showMainScreen()
}
För lagring av mer komplexa inställningar, som ett strukturerat Profile-objekt, rekommenderas användning av Codable-protokollet och JSONEncoder/JSONDecoder. Objektet serialiseras till Data via JSONEncoder, sparas via set(_:forKey:), och vid läsning deserialiseras det från Data tillbaka till objekt via JSONDecoder. Detta tillvägagångssätt gör det möjligt att lagra komplexa strukturer i UserDefaults utan förlust av typsäkerhet.
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)
}
}
// Användning
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")
Det är viktigt att komma ihåg att NSUserDefaults inte är avsett för lagring av stora datamängder. Apple rekommenderar att begränsa storleken på lagrad data till några tiotals kilobyte. För lagring av stora objekt (bilder, dokument, serialiserade modeller) bör FileManager med Documents-katalogen eller CoreData användas. Dessutom stöder UserDefaults inte versionshantering av dataschemat — när strukturen för en Codable-modell ändras kan gamla data inte deserialiseras, och detta måste hanteras i appkoden.
Vanliga frågor
Båda är nyckel-värde-lager, men NSUserDefaults stöder fler typer (Data, Date, Array, Dictionary) och synkroniseras automatiskt med iCloud. SharedPreferences lagrar data i XML, NSUserDefaults i plist-format. NSUserDefaults har ett domänsystem med kaskadsökning, SharedPreferences använder en enkel platt struktur med filnamn.
Nej, NSUserDefaults lagrar data i öppen form utan kryptering. För lösenord, tokens och krypteringsnycklar, använd Keychain som krypterar data på Secure Enclave-nivå. Keychain stöder även åtkomstattribut som biometrisk autentisering (Face ID / Touch ID) innan hemligheten läses.
För synkronisering mellan enheter av samma användare, använd NSUbiquitousKeyValueStore — iClouds molnbaserade nyckel-värde-lager. Data som skrivs till denna tjänst på en enhet visas automatiskt på alla andra enheter med samma iCloud-konto. Maximal volym — 1 MB per app, 1024 nycklar.
För att ta bort all data, anropa metoden removePersistentDomain(forName:) med appens Bundle Identifier. För att ta bort enskilda värden, använd removeObject(forKey:). För fullständig återställning av appinställningar: UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!). Alla borttagningar tillämpas omedelbart på minnescachen.
Apple sätter ingen strikt gräns för storleken på NSUserDefaults, men det rekommenderas att inte överstiga 100 KB för den totala volymen av all lagrad data. För stora volymer, använd CoreData eller FileManager. Vid lagring av mer än 1 MB data kan läsprestandan vid appstart märkbart minska.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också