NSUserDefaults — cos’è, API UserDefaults e lavoro con le impostazioni iOS

Autore: IT Sectr Pubblicato: 2026-03-12 Tempo di lettura: 10 min

NSUserDefaults è un archivio dati chiave-valore su iOS, watchOS, tvOS e macOS, progettato per salvare impostazioni e configurazioni dell’applicazione. I dati sono memorizzati in un file plist nella sandbox dell’applicazione e si sincronizzano automaticamente con iCloud tramite NSUbiquitousKeyValueStore. Secondo la documentazione ufficiale di Apple Developer, 2025, NSUserDefaults supporta la memorizzazione di tipi primitivi: String, Int, Bool, Float, Double, Data, Date, Array e Dictionary. La classe è stata rinominata in UserDefaults a partire da Swift 3, ma il suo nome Objective-C NSUserDefaults rimane ampiamente utilizzato nelle basi di codice e nella documentazione Apple.

Punti chiave

  • NSUserDefaults è un archivio chiave-valore su iOS e macOS per salvare semplici impostazioni dell’applicazione in un file plist.
  • Supporta nove tipi di dati: String, Int, Bool, Float, Double, Data, Date, Array e Dictionary.
  • I dati si sincronizzano automaticamente con iCloud tramite NSUbiquitousKeyValueStore con il supporto dello sviluppatore.
  • Utilizza un sistema di domini con ricerca a cascata lungo la catena di domini.
  • Per memorizzare dati sensibili, Apple raccomanda di utilizzare Keychain invece di NSUserDefaults.

Cos’è NSUserDefaults?

NSUserDefaults (UserDefaults in Swift) è il meccanismo integrato di Apple per memorizzare coppie chiave-valore in formato plist. È disponibile su tutte le piattaforme Apple: iOS, iPadOS, watchOS, tvOS e macOS. Il suo scopo principale è salvare le preferenze dell’utente, lo stato dell’interfaccia, i flag di primo avvio, le opzioni selezionate e altri dati semplici che persistono dopo i riavvii dell’applicazione.

Ogni applicazione iOS ha una sandbox isolata e NSUserDefaults è memorizzato nella directory Library/Preferences all’interno di questa sandbox in un file con il nome del Bundle Identifier. Il file plist contiene coppie chiave-valore dove la chiave è una stringa e il valore è uno dei tipi supportati. La dimensione del file non è limitata, ma Apple raccomanda di memorizzare solo impostazioni in UserDefaults, non grandi quantità di dati.

A partire da iOS 8, NSUserDefaults ha iniziato a supportare App Groups — archiviazione condivisa tra applicazioni dello stesso sviluppatore e le loro estensioni (widget, app companion watchOS). Per questo si utilizza l’inizializzatore init?(suiteName:) con un identificatore App Group. Ciò consente, ad esempio, a un widget Today di leggere le impostazioni dall’applicazione principale senza duplicare la logica di salvataggio.

Formato di archiviazione: plist sul dispositivo

Fisicamente, NSUserDefaults è memorizzato in un file plist binario in: {Sandbox}/Library/Preferences/com.example.myapp.plist. Il file utilizza il formato plist binario (NSPropertyListBinaryFormat_v1_0) per compattezza e velocità di lettura. Su macOS, il file può essere in formato XML per compatibilità. A differenza di SharedPreferences su Android, i file plist di UserDefaults possono contenere strutture annidate tramite Dictionary e Array.

I file NSUserDefaults non sono crittografati per impostazione predefinita. I dati sono memorizzati in testo semplice e possono essere letti con accesso fisico al dispositivo o tramite backup. Per memorizzare dati sensibili (password, token, chiavi di crittografia), Apple raccomanda vivamente di utilizzare Keychain, che crittografa automaticamente i dati a livello di sistema operativo.

Come funziona NSUserDefaults in iOS

NSUserDefaults funziona secondo il principio di caching in memoria con sincronizzazione periodica su disco. Al primo accesso all’istanza standard UserDefaults.standard, il sistema carica il file plist in RAM come Dictionary. Tutte le letture successive vengono eseguite dalla memoria. La scrittura avviene anch’essa prima in memoria, con sincronizzazione su disco che avviene periodicamente su un thread in background.

Le operazioni di scrittura utilizzano il metodo set(_:forKey:), che accetta un valore opzionale di tipo Any?. Il valore può essere nil — usato per rimuovere una chiave. Per la scrittura immediata su disco, in precedenza veniva utilizzato il metodo synchronize(), ma a partire da iOS 7 e OS X 10.9 non è più necessario — il sistema sincronizza automaticamente i dati a intervalli regolari. Apple ha dichiarato ufficialmente synchronize() ridondante nella sua documentazione.

Registri di UserDefaults e domini

NSUserDefaults utilizza un sistema di registri (domini) per organizzare la ricerca dei valori. Quando un’applicazione richiede un valore per chiave, UserDefaults controlla sequenzialmente i domini in un ordine specifico: prima NSArgumentDomain (argomenti della riga di comando), poi il dominio dell’Applicazione, poi NSGlobalDomain (impostazioni di sistema), poi i domini specifici della lingua e infine NSRegistrationDomain (valori predefiniti registrati tramite register(defaults:)).

swift
import Foundation

// Istanza standard di UserDefaults
let defaults = UserDefaults.standard

// Scrittura di valori
defaults.set("Anna Petrova", forKey: "username")
defaults.set(28, forKey: "age")
defaults.set(true, forKey: "isLoggedIn")

// Registrazione di valori predefiniti
defaults.register(defaults: [
    "theme": "system",
    "fontSize": 14
])

// Lettura con restituzione del valore predefinito
let theme = defaults.string(forKey: "theme") ?? "system"
let fontSize = defaults.integer(forKey: "fontSize")

Il dominio NSRegistrationDomain è un dominio programmatico che esiste solo in memoria e non viene persistito su disco. Viene utilizzato per impostare valori predefiniti che si applicano fino a quando l’applicazione scrive il proprio valore nel dominio dell’Applicazione. Ciò consente di creare un unico punto di configurazione per le impostazioni predefinite che possono essere modificate centralmente durante lo sviluppo.

Metodi principali di NSUserDefaults

NSUserDefaults fornisce un insieme di metodi tipizzati per leggere e scrivere dati: string(forKey:), integer(forKey:), bool(forKey:), float(forKey:), double(forKey:), data(forKey:), array(forKey:), dictionary(forKey:) e object(forKey:). Ogni metodo di lettura ha un corrispondente metodo di scrittura set(_:forKey:) con determinazione automatica del tipo del valore memorizzato. La versione Swift di UserDefaults utilizza tipizzazione forte, ma la versione Objective-C accetta e restituisce id.

Metodo di lettura (Swift)Tipo di datiValore predefinito
string(forKey:)String?nil
integer(forKey:)Int0
bool(forKey:)Boolfalse
float(forKey:)Float0.0
double(forKey:)Double0.0
data(forKey:)Data?nil

synchronize e la sua rilevanza

Il metodo synchronize() in NSUserDefaults forza la scrittura di tutte le modifiche dalla memoria al disco. Nelle prime versioni di iOS, questo metodo doveva essere chiamato dopo ogni scrittura per garantire la persistenza dei dati. A partire da iOS 7, il sistema sincronizza automaticamente UserDefaults su un thread in background e Apple ha ufficialmente dichiarato synchronize() ridondante. La chiamata di questo metodo non causa un errore ma non offre garanzie aggiuntive di persistenza.

Per monitorare le modifiche, NSUserDefaults fornisce la notifica UserDefaults.didChangeNotification e il metodo di osservazione KVO addObserver(_:forKeyPath:options:context:). In SwiftUI, è disponibile il Property Wrapper @AppStorage, che sincronizza automaticamente un valore in UserDefaults con l’aggiornamento dell’interfaccia utente. @AppStorage supporta gli stessi tipi di UserDefaults ed è il metodo preferito per lavorare con le impostazioni nelle applicazioni SwiftUI.

swift
// Osservazione delle modifiche tramite KVO
class SettingsViewModel: NSObject {
    override func observeValue(
        forKeyPath keyPath: String?,
        of object: Any?,
        change: [NSKeyValueChangeKey: Any]?,
        context: UnsafeMutableRawPointer?
    ) {
        guard let keyPath else { return }
        print("Chiave modificata: \(keyPath)")
    }
}

// SwiftUI - AppStorage
struct SettingsView: View {
    @AppStorage("theme") private var theme: String = "system"

    var body: some View {
        Picker("Tema", selection: $theme) {
            Text("Sistema").tag("system")
            Text("Chiaro").tag("light")
            Text("Scuro").tag("dark")
        }
    }
}

Per lavorare con App Groups (archiviazione condivisa tra un’applicazione e le sue estensioni), utilizzare l’inizializzatore UserDefaults(suiteName:) con un identificatore App Group. Ad esempio, “group.com.example.myapp”. I dati scritti in questa istanza sono accessibili dall’applicazione principale, dal widget, dall’app companion watchOS e da altre estensioni appartenenti allo stesso App Group. Ogni istanza suite è memorizzata in un file plist separato.

NSUserDefaults vs alternative di archiviazione

Nonostante la sua comodità e semplicità, NSUserDefaults non è una soluzione di archiviazione universale per tutti i tipi di dati su iOS. A seconda del volume, della criticità e dei requisiti di sicurezza, Apple fornisce diverse alternative, ciascuna ottimizzata per un caso d’uso specifico.

SoluzioneQuando utilizzareLimitazioni
NSUserDefaultsImpostazioni dell’interfaccia e configurazioneNon adatto per grandi dati o segreti
KeychainPassword, token, chiavi di crittografiaPiù complesso da usare, più lento
CoreDataDati strutturati con relazioniEccessivo per 10–20 impostazioni
FileManagerDocumenti, immagini, dati binariRichiede gestione manuale dei file
CloudKitSincronizzazione cloud tra dispositiviRichiede account iCloud e connessione di rete

Keychain — archiviazione sicura

Keychain è l’archiviazione sicura di Apple per dati riservati. A differenza di NSUserDefaults, tutti i dati in Keychain sono crittografati a livello di sistema operativo utilizzando la crittografia hardware di Secure Enclave sui dispositivi compatibili. Keychain si blocca e sblocca automaticamente con il dispositivo e supporta la condivisione dell’accesso tra applicazioni dello stesso sviluppatore tramite Keychain Access Groups.

Lo svantaggio principale di Keychain è la complessità dell’API. Per semplicemente salvare una stringa, è necessario creare una query SecItemAdd specificando gli attributi: classe (kSecClassGenericPassword), servizio (kSecAttrService), account (kSecAttrAccount) e i dati effettivi (kSecValueData). Per semplificare il lavoro con Keychain, esistono wrapper di terze parti come KeychainAccess e SwiftKeychainWrapper che forniscono un’interfaccia chiave-valore comoda simile a UserDefaults.

Esempio di utilizzo di NSUserDefaults in Swift

Consideriamo un esempio pratico: salvare e ripristinare lo stato di onboarding (schermate di benvenuto) in un’applicazione iOS utilizzando NSUserDefaults. Al primo avvio, l’utente vede le schermate di onboarding; dopo averle completate, un flag viene salvato in UserDefaults. Negli avvii successivi, l’onboarding viene saltato. Per SwiftUI si utilizza @AppStorage; per UIKit, accesso diretto a UserDefaults.standard.

Salvare lo stato di onboarding

Creiamo un OnboardingManager che incapsula il lavoro con UserDefaults per memorizzare lo stato di onboarding. Il gestore fornisce una proprietà isOnboardingCompleted per verificare lo stato e un metodo markOnboardingCompleted per impostare il flag. La chiave di archiviazione è estratta in una costante per prevenire errori di battitura. Per i test unitari, il gestore utilizza un protocollo UserDefaultsProtocol, consentendo di sostituire l’archivio reale con un MockUserDefaults.

swift
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)
    }
}

// Utilizzo nell’applicazione
let onboardingManager = OnboardingManager()
if !onboardingManager.isOnboardingCompleted {
    showOnboarding()
} else {
    showMainScreen()
}

Per memorizzare impostazioni più complesse, come un oggetto Profile strutturato, si consiglia di utilizzare il protocollo Codable e JSONEncoder/JSONDecoder. L’oggetto viene serializzato in Data tramite JSONEncoder, salvato tramite set(_:forKey:), e alla lettura viene deserializzato da Data nell’oggetto tramite JSONDecoder. Questo approccio consente di memorizzare strutture complesse in UserDefaults senza perdere la sicurezza dei tipi.

swift
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)
    }
}

// Utilizzo
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")

È importante ricordare che NSUserDefaults non è progettato per memorizzare grandi quantità di dati. Apple raccomanda di limitare i dati memorizzati a poche decine di kilobyte. Per memorizzare oggetti di grandi dimensioni (immagini, documenti, modelli serializzati), utilizzare FileManager con la directory Documents o CoreData. Inoltre, UserDefaults non supporta il versioning dello schema dei dati — quando la struttura del modello Codable cambia, i vecchi dati potrebbero non deserializzarsi e questo deve essere gestito nel codice dell’applicazione.

Domande frequenti

In cosa NSUserDefaults si differenzia da SharedPreferences su Android?

Entrambi sono archivi chiave-valore, ma NSUserDefaults supporta più tipi (Data, Date, Array, Dictionary) e si sincronizza automaticamente con iCloud. SharedPreferences memorizza i dati in XML, NSUserDefaults in formato plist. NSUserDefaults ha un sistema di domini con ricerca a cascata, mentre SharedPreferences utilizza una semplice struttura piatta con nomi di file.

È sicuro memorizzare le password in NSUserDefaults?

No, NSUserDefaults memorizza i dati in testo semplice senza crittografia. Per password, token e chiavi di crittografia, utilizzare Keychain, che crittografa i dati a livello di Secure Enclave. Keychain supporta anche attributi di accesso come l’autenticazione biometrica (Face ID / Touch ID) prima di leggere un segreto.

Come sincronizzare NSUserDefaults tra dispositivi?

Per la sincronizzazione tra dispositivi dello stesso utente, utilizzare NSUbiquitousKeyValueStore — l’archivio chiave-valore cloud iCloud. I dati scritti in questo servizio su un dispositivo appaiono automaticamente su tutti gli altri dispositivi con lo stesso account iCloud. Capacità massima: 1 MB per applicazione, 1024 chiavi.

Come eliminare tutti i dati da NSUserDefaults?

Per eliminare tutti i dati, chiamare il metodo removePersistentDomain(forName:) con il Bundle Identifier dell’applicazione. Per rimuovere singoli valori, utilizzare removeObject(forKey:). Per un reset completo delle impostazioni: UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!). Tutte le eliminazioni vengono applicate immediatamente alla cache in memoria.

Qual è la dimensione massima dei dati in NSUserDefaults?

Apple non impone un limite rigido alla dimensione di NSUserDefaults, ma si raccomanda di non superare 100 KB di volume totale di tutti i dati memorizzati. Per volumi maggiori, utilizzare CoreData o FileManager. Quando si memorizzano più di 1 MB di dati, le prestazioni di lettura all’avvio dell’applicazione possono diminuire notevolmente.

Riepilogo

  • NSUserDefaults è l’archivio chiave-valore integrato di Apple per semplici impostazioni di applicazioni in formato plist.
  • Supporta nove tipi di dati: String, Int, Bool, Float, Double, Data, Date, Array e Dictionary.
  • Utilizza un sistema di domini con ricerca a cascata attraverso NSRegistrationDomain, NSGlobalDomain e il dominio dell’Applicazione.
  • Per la sincronizzazione tra dispositivi Apple, Apple fornisce NSUbiquitousKeyValueStore con un limite di 1 MB per applicazione.
  • Per la sicurezza, utilizzare Keychain per password e token, non NSUserDefaults.
  • In SwiftUI, il metodo preferito è il Property Wrapper @AppStorage con sincronizzazione automatica dell’interfaccia utente.
  • Per dati grandi o strutturati, scegliere CoreData o FileManager invece di NSUserDefaults.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche