NSUserDefaults is een sleutel-waarde gegevensopslag in iOS, watchOS, tvOS en macOS, bedoeld voor het opslaan van instellingen en configuraties van de app. Gegevens worden opgeslagen in een plist-bestand in de sandbox van de app en worden automatisch gesynchroniseerd met iCloud via NSUbiquitousKeyValueStore. Volgens de officiële documentatie Apple Developer, 2025, ondersteunt NSUserDefaults het opslaan van primitieve typen: String, Int, Bool, Float, Double, Data, Date, Array en Dictionary. De klasse is hernoemd naar UserDefaults vanaf Swift 3, maar de Objective-C naam NSUserDefaults blijft veel gebruikt in de codebase en Apple documentatie.
Belangrijkste punten
NSUserDefaults (UserDefaults in Swift) is een ingebouwd Apple mechanisme voor het opslaan van sleutel-waarde paren in plist-formaat. Het is beschikbaar op alle Apple platforms: iOS, iPadOS, watchOS, tvOS en macOS. Het hoofddoel is het opslaan van gebruikersvoorkeuren, interface status, first-launch vlaggen, geselecteerde opties en andere eenvoudige gegevens die een herstart van de app overleven.
Elke iOS-app heeft een geïsoleerde sandbox en NSUserDefaults wordt opgeslagen in de map Library/Preferences in deze sandbox in een bestand met de naam Bundle Identifier. Het plist-bestand bevat sleutel-waarde paren, waarbij de sleutel een string is en de waarde een van de ondersteunde typen. De bestandsgrootte is niet beperkt, maar Apple raadt aan alleen instellingen op te slaan in UserDefaults, niet grote hoeveelheden gegevens.
Sinds iOS 8 ondersteunt NSUserDefaults App Groups — gedeelde opslag tussen apps van dezelfde ontwikkelaar en hun extensies (widgets, watchOS companion apps). Hiervoor wordt de initialisator init?(suiteName:) met de App Group identifier gebruikt. Dit stelt bijvoorbeeld een widget op het Today-scherm in staat om instellingen uit de hoofdapp te lezen zonder de opslaglogica te dupliceren.
Fysiek wordt NSUserDefaults opgeslagen in een binair plist-bestand op het pad: {Sandbox}/Library/Preferences/com.example.myapp.plist. Het bestand gebruikt het binaire plist-formaat (NSPropertyListBinaryFormat_v1_0) voor compactheid en leessnelheid. Op macOS kan het bestand in XML-formaat zijn voor compatibiliteit. In tegenstelling tot SharedPreferences op Android, kunnen UserDefaults plist-bestanden geneste structuren bevatten via Dictionary en Array.
NSUserDefaults bestanden worden standaard niet versleuteld. Gegevens worden in open vorm opgeslagen en kunnen worden gelezen bij fysieke toegang tot het apparaat of via een back-up. Voor het opslaan van gevoelige gegevens (wachtwoorden, tokens, versleutelingssleutels) beveelt Apple ten zeerste het gebruik van Keychain aan, dat gegevens automatisch versleutelt op het niveau van het besturingssysteem.
NSUserDefaults werkt volgens het principe van caching in het geheugen met periodieke synchronisatie naar de schijf. Bij de eerste toegang tot de standaardinstantie UserDefaults.standard laadt het systeem het plist-bestand in het RAM-geheugen als Dictionary. Alle volgende lezingen worden uit het geheugen uitgevoerd. Schrijven gebeurt ook eerst in het geheugen, en synchronisatie naar de schijf vindt periodiek plaats op de achtergrond.
Schrijfbewerkingen gebruiken de methode set(_:forKey:), die een optionele waarde van het type Any? accepteert. De waarde kan nil zijn — om een sleutel te verwijderen. Voor onmiddellijk schrijven naar de schijf werd vroeger de methode synchronize() gebruikt, maar vanaf iOS 7 en OS X 10.9 is dit niet meer nodig — het systeem synchroniseert gegevens automatisch met regelmatige tussenpozen. Apple heeft synchronize() officieel overbodig verklaard in zijn documentatie.
NSUserDefaults gebruikt een systeem van registers (domeinen) voor het organiseren van het zoeken naar waarden. Wanneer de app een waarde opvraagt bij een sleutel, controleert UserDefaults achtereenvolgens de domeinen in een bepaalde volgorde: eerst NSArgumentDomain (commandoregel argumenten), dan het toepassingsdomein (Application), dan NSGlobalDomain (systeeminstellingen), dan taalspecifieke domeinen en ten slotte NSRegistrationDomain (standaardwaarden geregistreerd via register(defaults:)).
import Foundation
// Standaard UserDefaults-instantie
let defaults = UserDefaults.standard
// Waarden schrijven
defaults.set("Anna Petrova", forKey: "username")
defaults.set(28, forKey: "age")
defaults.set(true, forKey: "isLoggedIn")
// Registratie van standaardwaarden
defaults.register(defaults: [
"theme": "system",
"fontSize": 14
])
// Lezen met terugkeer van standaardwaarde
let theme = defaults.string(forKey: "theme") ?? "system"
let fontSize = defaults.integer(forKey: "fontSize")
Het domein NSRegistrationDomain is een softwaredomein dat alleen in het RAM-geheugen bestaat en niet op de schijf wordt opgeslagen. Het wordt gebruikt om standaardwaarden in te stellen die actief zijn totdat de app zijn eigen waarde in het toepassingsdomein schrijft. Dit maakt het mogelijk om een enkel configuratiepunt voor standaardinstellingen te creëren dat centraal kan worden gewijzigd in de ontwikkelingsfase.
NSUserDefaults biedt een reeks getypeerde methoden voor het lezen en schrijven van gegevens: string(forKey:), integer(forKey:), bool(forKey:), float(forKey:), double(forKey:), data(forKey:), array(forKey:), dictionary(forKey:) en object(forKey:). Elke leesmethode heeft een corresponderende schrijfmethode set(_:forKey:) met automatische bepaling van het type opgeslagen waarde. De Swift-versie van UserDefaults gebruikt strikte typering, maar de Objective-C-versie accepteert en retourneert id.
| Leesmethode (Swift) | Gegevenstype | Standaardwaarde |
|---|---|---|
| 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 |
De methode synchronize() in NSUserDefaults dwingt het schrijven van alle wijzigingen uit het geheugen naar de schijf af. In vroege versies van iOS moest deze methode na elke schrijfbewerking worden aangeroepen om het opslaan van gegevens te garanderen. Vanaf iOS 7 synchroniseert het systeem UserDefaults automatisch op de achtergrond en Apple heeft synchronize() officieel overbodig verklaard. Het aanroepen van deze methode veroorzaakt geen fout, maar geeft geen extra garanties voor het bewaren van gegevens.
Voor het monitoren van wijzigingen biedt NSUserDefaults de notificatie UserDefaults.didChangeNotification en de KVO-waarnemingsmethode addObserver(_:forKeyPath:options:context:). In SwiftUI is de Property Wrapper @AppStorage beschikbaar, die automatisch de waarde in UserDefaults synchroniseert met UI-updates. @AppStorage ondersteunt dezelfde typen als UserDefaults en is de voorkeursmanier om met instellingen te werken in SwiftUI-apps.
// Wijzigingen observeren 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("Sleutel gewijzigd: \(keyPath)")
}
}
// SwiftUI - AppStorage
struct SettingsView: View {
@AppStorage("theme") private var theme: String = "system"
var body: some View {
Picker("Thema", selection: $theme) {
Text("Systeem").tag("system")
Text("Licht").tag("light")
Text("Donker").tag("dark")
}
}
}
Voor het werken met App Groups (gedeelde opslag tussen app en extensies) wordt de initialisator UserDefaults(suiteName:) met de App Group identifier gebruikt. Bijvoorbeeld "group.com.example.myapp". Gegevens die naar deze instantie worden geschreven, zijn toegankelijk vanuit de hoofdapp, widget, watchOS companion app en andere extensies die tot dezelfde App Group behoren. Elke suite-instantie wordt opgeslagen in een apart plist-bestand.
Ondanks het gemak en de eenvoud is NSUserDefaults geen universele opslag voor alle gegevenstypen op iOS. Afhankelijk van de omvang, kritikaliteit en beveiligingseisen biedt Apple verschillende alternatieven, elk geoptimaliseerd voor een specifiek gebruiksscenario.
| Oplossing | Wanneer gebruiken | Beperkingen |
|---|---|---|
| NSUserDefaults | Interface-instellingen en configuratie | Niet geschikt voor grote gegevens en geheimen |
| Keychain | Wachtwoorden, tokens, versleutelingssleutels | Complexer in gebruik, langzamer |
| CoreData | Gestructureerde gegevens met relaties | Overbodig voor 10-20 instellingen |
| FileManager | Documenten, afbeeldingen, binaire gegevens | Vereist handmatig bestandsbeheer |
| CloudKit | Cloudsynchronisatie tussen apparaten | Vereist iCloud-account en netwerkverbinding |
Keychain is een beveiligde Apple-opslag voor vertrouwelijke gegevens. In tegenstelling tot NSUserDefaults worden alle gegevens in Keychain versleuteld op het niveau van het besturingssysteem met behulp van hardwarematige Secure Enclave-versleuteling op compatibele apparaten. Keychain wordt automatisch vergrendeld en ontgrendeld met het apparaat en ondersteunt toegangsdeling tussen apps van dezelfde ontwikkelaar via Keychain Access Groups.
Het grootste nadeel van Keychain is de complexiteit van de API. Om eenvoudig een string op te slaan, moet een SecItemAdd-aanvraag worden gemaakt met specificatie van attributen: klasse (kSecClassGenericPassword), service (kSecAttrService), account (kSecAttrAccount) en de gegevens zelf (kSecValueData). Om het werken met Keychain te vereenvoudigen, bestaan er externe wrappers zoals KeychainAccess en SwiftKeychainWrapper, die een handige sleutel-waarde interface bieden vergelijkbaar met UserDefaults.
Laten we een praktisch voorbeeld bekijken: het opslaan en herstellen van de onboarding-status (welkomstschermen) in een iOS-app met behulp van NSUserDefaults. Bij de eerste start ziet de gebruiker de onboarding-schermen, na het doorlopen wordt een vlag opgeslagen in UserDefaults. Bij volgende starts wordt onboarding overgeslagen. Voor SwiftUI wordt @AppStorage gebruikt, voor UIKit — directe toegang tot UserDefaults.standard.
Laten we een manager OnboardingManager maken die het werken met UserDefaults inkapselt voor het opslaan van de onboarding-status. De manager biedt de eigenschap isOnboardingCompleted voor statuscontrole en de methode markOnboardingCompleted voor het instellen van de vlag. De opslagsleutel is in een constante geplaatst om typefouten te voorkomen. Voor unittesten gebruikt de manager het protocol UserDefaultsProtocol, waardoor de echte opslag kan worden vervangen door 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)
}
}
// Gebruik in de app
let onboardingManager = OnboardingManager()
if !onboardingManager.isOnboardingCompleted {
showOnboarding()
} else {
showMainScreen()
}
Voor het opslaan van complexere instellingen, zoals een gestructureerd Profile-object, wordt het gebruik van het Codable protocol en JSONEncoder/JSONDecoder aanbevolen. Het object wordt via JSONEncoder naar Data geserialiseerd, opgeslagen via set(_:forKey:), en bij het lezen wordt het uit Data terug naar het object gedeserialiseerd via JSONDecoder. Deze aanpak maakt het mogelijk om complexe structuren in UserDefaults op te slaan zonder verlies van typeveiligheid.
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)
}
}
// Gebruik
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")
Het is belangrijk om te onthouden dat NSUserDefaults niet bedoeld is voor het opslaan van grote hoeveelheden gegevens. Apple raadt aan de omvang van opgeslagen gegevens te beperken tot enkele tientallen kilobytes. Voor het opslaan van grote objecten (afbeeldingen, documenten, geserialiseerde modellen) moet FileManager met de Documents-map of CoreData worden gebruikt. Bovendien ondersteunt UserDefaults geen versiebeheer van het gegevensschema — bij wijziging van de Codable-modelstructuur kunnen oude gegevens niet worden gedeserialiseerd en dit moet in de app-code worden afgehandeld.
Veelgestelde vragen
Beide zijn sleutel-waarde opslagen, maar NSUserDefaults ondersteunt meer typen (Data, Date, Array, Dictionary) en synchroniseert automatisch met iCloud. SharedPreferences slaat gegevens op in XML, NSUserDefaults in plist-formaat. NSUserDefaults heeft een domeinsysteem met trapsgewijs zoeken, SharedPreferences gebruikt een eenvoudige platte structuur met bestandsnamen.
Nee, NSUserDefaults slaat gegevens in open vorm op zonder versleuteling. Voor wachtwoorden, tokens en versleutelingssleutels gebruikt u Keychain, dat gegevens versleutelt op Secure Enclave-niveau. Keychain ondersteunt ook toegangsattributen zoals biometrische authenticatie (Face ID / Touch ID) voor het lezen van geheimen.
Voor synchronisatie tussen apparaten van dezelfde gebruiker gebruikt u NSUbiquitousKeyValueStore — de iCloud cloud sleutel-waarde opslag. Gegevens die naar deze service op een apparaat worden geschreven, verschijnen automatisch op alle andere apparaten van hetzelfde iCloud-account. Maximaal volume — 1 MB per app, 1024 sleutels.
Om alle gegevens te verwijderen, roept u de methode removePersistentDomain(forName:) aan met de Bundle Identifier van de app. Voor het verwijderen van afzonderlijke waarden gebruikt u removeObject(forKey:). Voor het volledig resetten van app-instellingen: UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!). Alle verwijderingen worden onmiddellijk toegepast op de geheugencache.
Apple stelt geen strikte limiet voor de grootte van NSUserDefaults, maar het wordt aanbevolen om niet meer dan 100 KB aan totale opgeslagen gegevens te hebben. Voor grote volumes gebruikt u CoreData of FileManager. Bij het opslaan van meer dan 1 MB aan gegevens kan de leesprestaties bij het starten van de app merkbaar afnemen.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook