NSUserDefaults: qué es, API de UserDefaults y trabajo con configuraciones de iOS

Autor: IT Sectr Publicado: 2026-03-12 Tiempo de lectura: 10 min

NSUserDefaults es un almacenamiento de datos clave-valor en iOS, watchOS, tvOS y macOS, diseñado para guardar configuraciones y preferencias de la aplicación. Los datos se almacenan en un archivo plist dentro del sandbox de la aplicación y se sincronizan automáticamente con iCloud a través de NSUbiquitousKeyValueStore. Según la documentación oficial de Apple Developer, 2025, NSUserDefaults admite el almacenamiento de tipos primitivos: String, Int, Bool, Float, Double, Data, Date, Array y Dictionary. La clase fue renombrada a UserDefaults a partir de Swift 3, pero su nombre en Objective-C NSUserDefaults sigue siendo ampliamente utilizado en bases de código y documentación de Apple.

Puntos Clave

  • NSUserDefaults es un almacenamiento clave-valor en iOS y macOS para guardar configuraciones simples de la aplicación en un archivo plist.
  • Admite nueve tipos de datos: String, Int, Bool, Float, Double, Data, Date, Array y Dictionary.
  • Los datos se sincronizan automáticamente con iCloud a través de NSUbiquitousKeyValueStore con soporte del desarrollador.
  • Utiliza un sistema de dominios con búsqueda en cascada a lo largo de la cadena de dominios.
  • Para almacenar datos sensibles, Apple recomienda usar Keychain en lugar de NSUserDefaults.

¿Qué es NSUserDefaults?

NSUserDefaults (UserDefaults en Swift) es el mecanismo integrado de Apple para almacenar pares clave-valor en formato plist. Está disponible en todas las plataformas Apple: iOS, iPadOS, watchOS, tvOS y macOS. Su propósito principal es guardar las preferencias del usuario, el estado de la interfaz, los indicadores de primer inicio, las opciones seleccionadas y otros datos simples que persisten entre reinicios de la aplicación.

Cada aplicación de iOS tiene un sandbox aislado, y NSUserDefaults se almacena en el directorio Library/Preferences dentro de este sandbox en un archivo con el nombre del Bundle Identifier. El archivo plist contiene pares clave-valor donde la clave es una cadena y el valor es uno de los tipos admitidos. El tamaño del archivo no está limitado, pero Apple recomienda almacenar solo configuraciones en UserDefaults, no grandes cantidades de datos.

A partir de iOS 8, NSUserDefaults comenzó a admitir App Groups, un almacenamiento compartido entre aplicaciones del mismo desarrollador y sus extensiones (widgets, aplicaciones complementarias de watchOS). Para ello se usa el inicializador init?(suiteName:) con un identificador de App Group. Esto permite, por ejemplo, que un widget en la pantalla Today lea las configuraciones de la aplicación principal sin duplicar la lógica de guardado.

Formato de almacenamiento: plist en el dispositivo

Físicamente, NSUserDefaults se almacena en un archivo plist binario en: {Sandbox}/Library/Preferences/com.example.myapp.plist. El archivo utiliza el formato plist binario (NSPropertyListBinaryFormat_v1_0) para compacidad y velocidad de lectura. En macOS, el archivo puede estar en formato XML para compatibilidad. A diferencia de SharedPreferences en Android, los archivos plist de UserDefaults pueden contener estructuras anidadas mediante Dictionary y Array.

Los archivos de NSUserDefaults no están cifrados de forma predeterminada. Los datos se almacenan en texto plano y pueden leerse con acceso físico al dispositivo o mediante una copia de seguridad. Para almacenar datos sensibles (contraseñas, tokens, claves de cifrado), Apple recomienda encarecidamente usar Keychain, que cifra los datos automáticamente a nivel del sistema operativo.

Cómo funciona NSUserDefaults en iOS

NSUserDefaults funciona según el principio de almacenamiento en caché en memoria con sincronización periódica en disco. En el primer acceso a la instancia estándar UserDefaults.standard, el sistema carga el archivo plist en la RAM como un Dictionary. Todas las lecturas posteriores se realizan desde la memoria. La escritura también ocurre primero en memoria, y la sincronización en disco se realiza periódicamente en un hilo en segundo plano.

Las operaciones de escritura utilizan el método set(_:forKey:), que acepta un valor opcional de tipo Any?. El valor puede ser nil, utilizado para eliminar una clave. Para la escritura inmediata en disco, anteriormente se usaba el método synchronize(), pero a partir de iOS 7 y OS X 10.9 ya no es necesario: el sistema sincroniza los datos automáticamente en intervalos regulares. Apple declaró oficialmente synchronize() como redundante en su documentación.

Registros de UserDefaults y dominios

NSUserDefaults utiliza un sistema de registros (dominios) para organizar la búsqueda de valores. Cuando una aplicación solicita un valor por clave, UserDefaults verifica secuencialmente los dominios en un orden específico: primero NSArgumentDomain (argumentos de línea de comandos), luego el dominio de la Aplicación, luego NSGlobalDomain (configuraciones del sistema), luego los dominios específicos del idioma y finalmente NSRegistrationDomain (valores predeterminados registrados mediante register(defaults:)).

swift
import Foundation

// Instancia estándar de UserDefaults
let defaults = UserDefaults.standard

// Escritura de valores
defaults.set("Ana Petrova", forKey: "username")
defaults.set(28, forKey: "age")
defaults.set(true, forKey: "isLoggedIn")

// Registro de valores predeterminados
defaults.register(defaults: [
    "theme": "system",
    "fontSize": 14
])

// Lectura con devolución de valor predeterminado
let theme = defaults.string(forKey: "theme") ?? "system"
let fontSize = defaults.integer(forKey: "fontSize")

El dominio NSRegistrationDomain es un dominio programático que existe solo en la memoria y no se persiste en disco. Se utiliza para establecer valores predeterminados que aplican hasta que la aplicación escribe su propio valor en el dominio de la Aplicación. Esto permite crear un punto único de configuración para los valores predeterminados que se pueden cambiar centralizadamente durante el desarrollo.

Métodos principales de NSUserDefaults

NSUserDefaults proporciona un conjunto de métodos tipificados para leer y escribir datos: string(forKey:), integer(forKey:), bool(forKey:), float(forKey:), double(forKey:), data(forKey:), array(forKey:), dictionary(forKey:) y object(forKey:). Cada método de lectura tiene un método de escritura correspondiente set(_:forKey:) con determinación automática del tipo del valor almacenado. La versión Swift de UserDefaults usa tipado fuerte, pero la versión Objective-C acepta y devuelve id.

Método de lectura (Swift)Tipo de datosValor predeterminado
string(forKey:)String?nil
integer(forKey:)Int0
bool(forKey:)Boolfalse
float(forKey:)Float0.0
double(forKey:)Double0.0
data(forKey:)Data?nil

synchronize y su relevancia

El método synchronize() en NSUserDefaults fuerza la escritura de todos los cambios de la memoria al disco. En versiones anteriores de iOS, este método debía llamarse después de cada escritura para garantizar la persistencia de los datos. A partir de iOS 7, el sistema sincroniza UserDefaults automáticamente en un hilo en segundo plano, y Apple declaró oficialmente synchronize() como redundante. Llamar a este método no causa un error, pero no ofrece garantías adicionales de persistencia.

Para monitorear cambios, NSUserDefaults proporciona la notificación UserDefaults.didChangeNotification y el método de observación KVO addObserver(_:forKeyPath:options:context:). En SwiftUI, está disponible el Property Wrapper @AppStorage, que sincroniza automáticamente un valor en UserDefaults con la actualización de la UI. @AppStorage admite los mismos tipos que UserDefaults y es la forma preferida de trabajar con configuraciones en aplicaciones SwiftUI.

swift
// Observación de cambios mediante KVO
class SettingsViewModel: NSObject {
    override func observeValue(
        forKeyPath keyPath: String?,
        of object: Any?,
        change: [NSKeyValueChangeKey: Any]?,
        context: UnsafeMutableRawPointer?
    ) {
        guard let keyPath else { return }
        print("Clave cambiada: \(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("Claro").tag("light")
            Text("Oscuro").tag("dark")
        }
    }
}

Para trabajar con App Groups (almacenamiento compartido entre una aplicación y sus extensiones), se usa el inicializador UserDefaults(suiteName:) con un identificador de App Group. Por ejemplo, “group.com.example.myapp”. Los datos escritos en esta instancia son accesibles desde la aplicación principal, el widget, la aplicación complementaria de watchOS y otras extensiones que pertenecen al mismo App Group. Cada instancia de suite se almacena en un archivo plist separado.

NSUserDefaults vs alternativas de almacenamiento

A pesar de su conveniencia y simplicidad, NSUserDefaults no es una solución de almacenamiento universal para todos los tipos de datos en iOS. Dependiendo del volumen, la criticidad y los requisitos de seguridad, Apple proporciona varias alternativas, cada una optimizada para un caso de uso específico.

SoluciónCuándo usarLimitaciones
NSUserDefaultsConfiguraciones de interfaz y preferenciasNo apto para grandes datos o secretos
KeychainContraseñas, tokens, claves de cifradoMás complejo de usar, más lento
CoreDataDatos estructurados con relacionesExcesivo para 10–20 configuraciones
FileManagerDocumentos, imágenes, datos binariosRequiere gestión manual de archivos
CloudKitSincronización en la nube entre dispositivosRequiere cuenta de iCloud y conexión de red

Keychain — almacenamiento seguro

Keychain es el almacenamiento seguro de Apple para datos confidenciales. A diferencia de NSUserDefaults, todos los datos en Keychain están cifrados a nivel del sistema operativo mediante el cifrado de hardware de Secure Enclave en dispositivos compatibles. Keychain se bloquea y desbloquea automáticamente con el dispositivo y admite el uso compartido de acceso entre aplicaciones del mismo desarrollador mediante Keychain Access Groups.

La principal desventaja de Keychain es la complejidad de su API. Para guardar simplemente una cadena, es necesario crear una consulta SecItemAdd especificando atributos: clase (kSecClassGenericPassword), servicio (kSecAttrService), cuenta (kSecAttrAccount) y los datos reales (kSecValueData). Para simplificar el trabajo con Keychain, existen envoltorios de terceros como KeychainAccess y SwiftKeychainWrapper que proporcionan una interfaz clave-valor conveniente similar a UserDefaults.

Ejemplo de uso de NSUserDefaults en Swift

Consideremos un ejemplo práctico: guardar y restaurar el estado de onboarding (pantallas de bienvenida) en una aplicación iOS usando NSUserDefaults. En el primer inicio, el usuario ve las pantallas de onboarding; después de completarlas, se guarda un indicador en UserDefaults. En inicios posteriores, el onboarding se omite. Para SwiftUI se usa @AppStorage; para UIKit, acceso directo a UserDefaults.standard.

Guardar el estado de onboarding

Creemos un OnboardingManager que encapsule el trabajo con UserDefaults para almacenar el estado del onboarding. El administrador proporciona una propiedad isOnboardingCompleted para verificar el estado y un método markOnboardingCompleted para establecer el indicador. La clave de almacenamiento se extrae en una constante para evitar errores tipográficos. Para pruebas unitarias, el administrador usa un protocolo UserDefaultsProtocol que permite reemplazar el almacenamiento real por 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)
    }
}

// Uso en la aplicación
let onboardingManager = OnboardingManager()
if !onboardingManager.isOnboardingCompleted {
    showOnboarding()
} else {
    showMainScreen()
}

Para almacenar configuraciones más complejas, como un objeto Profile estructurado, se recomienda usar el protocolo Codable y JSONEncoder/JSONDecoder. El objeto se serializa a Data mediante JSONEncoder, se guarda mediante set(_:forKey:), y al leer se deserializa de Data nuevamente al objeto mediante JSONDecoder. Este enfoque permite almacenar estructuras complejas en UserDefaults sin perder la seguridad de tipos.

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

// Uso
let profile = UserProfile(name: "Ana", age: 28, preferences: ["theme": "dark"])
UserDefaults.standard.save(profile, forKey: "user_profile")
let loaded = UserDefaults.standard.load(UserProfile.self, forKey: "user_profile")

Es importante recordar que NSUserDefaults no está diseñado para almacenar grandes volúmenes de datos. Apple recomienda limitar los datos almacenados a unas pocas decenas de kilobytes. Para almacenar objetos grandes (imágenes, documentos, modelos serializados), use FileManager con el directorio Documents o CoreData. Además, UserDefaults no admite versionado de esquemas de datos: cuando cambia la estructura del modelo Codable, los datos antiguos pueden no deserializarse, y esto debe manejarse en el código de la aplicación.

Preguntas Frecuentes

¿En qué se diferencia NSUserDefaults de SharedPreferences en Android?

Ambos son almacenes clave-valor, pero NSUserDefaults admite más tipos (Data, Date, Array, Dictionary) y se sincroniza automáticamente con iCloud. SharedPreferences almacena datos en XML, NSUserDefaults en formato plist. NSUserDefaults tiene un sistema de dominios con búsqueda en cascada, mientras que SharedPreferences usa una estructura plana simple con nombres de archivo.

¿Es seguro almacenar contraseñas en NSUserDefaults?

No, NSUserDefaults almacena datos en texto plano sin cifrado. Para contraseñas, tokens y claves de cifrado, use Keychain, que cifra los datos a nivel de Secure Enclave. Keychain también admite atributos de acceso como autenticación biométrica (Face ID / Touch ID) antes de leer un secreto.

¿Cómo sincronizar NSUserDefaults entre dispositivos?

Para la sincronización entre dispositivos de un mismo usuario, use NSUbiquitousKeyValueStore, el almacén clave-valor en la nube de iCloud. Los datos escritos en este servicio en un dispositivo aparecen automáticamente en todos los demás dispositivos con la misma cuenta de iCloud. Capacidad máxima: 1 MB por aplicación, 1024 claves.

¿Cómo eliminar todos los datos de NSUserDefaults?

Para eliminar todos los datos, llame al método removePersistentDomain(forName:) con el Bundle Identifier de la aplicación. Para eliminar valores individuales, use removeObject(forKey:). Para un restablecimiento completo de la configuración: UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!). Todas las eliminaciones se aplican inmediatamente a la caché en memoria.

¿Cuál es el tamaño máximo de datos en NSUserDefaults?

Apple no establece un límite estricto para el tamaño de NSUserDefaults, pero se recomienda no superar los 100 KB de volumen total de todos los datos almacenados. Para volúmenes mayores, use CoreData o FileManager. Al almacenar más de 1 MB de datos, el rendimiento de lectura al iniciar la aplicación puede disminuir notablemente.

Resumen

  • NSUserDefaults es el almacenamiento clave-valor integrado de Apple para configuraciones simples de aplicaciones en formato plist.
  • Admite nueve tipos de datos: String, Int, Bool, Float, Double, Data, Date, Array y Dictionary.
  • Utiliza un sistema de dominios con búsqueda en cascada a través de NSRegistrationDomain, NSGlobalDomain y el dominio de la Aplicación.
  • Para la sincronización entre dispositivos Apple, Apple proporciona NSUbiquitousKeyValueStore con un límite de 1 MB por aplicación.
  • Para seguridad, use Keychain para contraseñas y tokens, no NSUserDefaults.
  • En SwiftUI, la forma preferida es el Property Wrapper @AppStorage con sincronización automática de la UI.
  • Para datos grandes o estructurados, elija CoreData o FileManager en lugar de NSUserDefaults.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también