¿Cuáles son las limitaciones de NSUserDefaults?

El almacenamiento permanente de datos en un iPhone generalmente se realiza con Core Data o sqlite3. La mayoría de las personas prefiere usar NSUserDefaults como almacenamiento para las preferencias de la aplicación, en lugar de usarlo como una base de datos normal (como sqlite).

Descubrí que una gran cantidad de datos se puede almacenar en NSUserDefaults, es extremadamente fácil de usar y rápido. Entonces, ¿por qué no usar esto como un almacenamiento permanente? ¿Cuáles son las limitaciones de NSUserDefaults como base de datos?

Actualizar:
Con frecuencia utilizo tres formas diferentes de guardar mis datos en el disco.

  • Datos básicos
  • Serializar objetos a los pilotos
  • NSUserDefaults

Ya no uso FMDB (o sqlite directamente). ¿Cuáles son las principales ventajas y desventajas de cada enfoque?

Algunas de las ventajas de NSUserDefaults que he encontrado:

  • La clasificación, agrupación, etc. se puede hacer fácilmente usando NSPredicate.
  • NSUserDefaults es seguro para subprocesos.
  • Se necesita una línea para recuperar y guardar datos en NSUserDefaults.

NSUserDefaults ofrece una curva de aprendizaje trivial y una implementación segura de subprocesos.

De lo contrario, he encontrado que Core Data es superior en todos los sentidos. Especialmente con respecto a la configuración de valores predeterminados y rutinas de migración.

Editar: Al parecer, NSUserDefaults “thread-safeness” parece provenir de las operaciones en ejecución en el hilo principal. Esto causó saltos de cuadros graves en una de mis aplicaciones; Terminé arrancando NSUserDefaults y reemplazándolo con un hilo NSMutableDictionary que se serializa en un archivo.

Sqlite3 es más útil para mantener grandes bases de datos y para acceder a los elementos de la base de datos. Puede ordenar los elementos de la base de datos Sqlite3, puede buscar muy rápidamente el elemento en Sqlite3 dtabase. ¡La base de datos Sqlite3 tiene muchos privilegios que NSUserDefaults no tenía!


NSUserDefaults vs Sqlite3

NSUserDefaults es para las preferencias del usuario, generalmente objetos básicos como NSString o NSNumber. Sqlite, la serialización de una colección de objetos en una lista de propiedades, o los datos centrales son todas opciones válidas para almacenar datos de usuario como los objetos modelo que ha creado.

No verá una diferencia de velocidad, pero aún así es mejor elegir el mecanismo correcto para lo que está haciendo. Si solo son preferencias, use NSUserDefaults, de lo contrario, serializaría sus objetos en un plist. Si eres nuevo en Cocoa, evitaría Core Data e incluso Sqlite al principio, para tener la oportunidad de aprender lo básico primero.


NSUserDefaults o Sqlite

Cuando desee almacenar una gran cantidad de datos con alguna relación, vaya a Sqlite si desea almacenar menos valor para NSUserDefaults. Sqlite ocupa algo de memoria, así que úsela solo si realmente necesita guardar datos complejos.


Usando NSUserDefaults para guardar una gran cantidad de datos del juego

Por lo general, NSUserDefaults se usa para guardar la configuración del juego. Para guardar los datos del juego, generalmente es mejor usar SQLite o puede crear un NSDictionary de objetos y guardar en el disco, aquí un par de publicaciones que pueden ayudar:

  1. http://www.cocos2d-iphone.org/forum/topic/9308
  2. http://www.cocos2d-iphone.org/forum/topic/9210

Para un proyecto en el que estoy trabajando actualmente, necesito configurar una gran base de datos (aproximadamente 400,000 registros). Si usa NSUserDefaults, debe agregar los registros que pueden demorar algunos minutos (según el dispositivo y la forma de importar sus datos). Si usa CoreData, simplemente puede copiar una base de datos precomstackda en el directorio de documentos de su aplicación y utilizarla de manera inmediata.

Es por eso que confío en CoreData.

Una de las ventajas de CoreData es que su objeto será un NSManagedObject con propiedades. Eso significa que cuando obtenga o establezca los valores tendrá autocompletar para ayudarlo con los nombres de las propiedades. También hace que el código sea más legible.

Mientras tanto, con NSUserDefaults, debe usar siempre los descriptores de valor-clave, usando cadenas para la clave.

Es decir:

myGlobalSettingsObject.lastLoginTime = @(now);

vs.

[[NSUserDefaults standardUserDefaults] setValue:@(now) forKey:@"lastLoginTime"];

¿Qué pasa si accidentalmente hace un error al escribir la clave en alguna parte? El comstackdor no te advertirá. ¿Qué pasa si alguien pone el tipo equivocado en alguna parte? El comstackdor no te advertirá.

P.ej:

[[NSUserDefaults standardUserDefaults] setValue:@"now" forKey:@"lastLoginTiem"]; ^ ^ ^^^^

… no causará ni advertencia ni error en el momento de la construcción … ¡peligroso!

Otros beneficios de usar un NSManagedObject serían que puede tener validación; puede garantizar valores no nulos; puede tener métodos personalizados getter y setter que puede usar para hacer algunas cosas interesantes; puede manejar la migración automática si cambia algo acerca de cómo se almacenan todos los valores; y su modelo de datos se convierte en parte de su repository, por lo que puede rastrear fácilmente el historial de cambios en él.

Mientras tanto, NSUserDefaults es rápido y sucio, y es ideal para pequeñas aplicaciones básicas, pero es muy primordial. Está bien para una aplicación pequeña, pero si tiene una gran aplicación, será difícil de administrar en comparación con el uso de datos básicos.

Lo único posible acerca de NSUserDefaults es que si su aplicación necesita eliminar su tienda CoreData o si no quiere complicarse con la implementación de CoreData seguro para subprocesos, es un mantenimiento menor en ese sentido.