2009-01-24 17 views
5

He estado experimentando resultados muy inconsistentes mientras desarrollaba una aplicación de iPhone y trato de guardar las preferencias a través del mecanismo NSUserDefaults estándar. Estoy utilizando el código casi directamente de libro de cocina del iPhone desarrollador por Erica Sadun (libro fantástico por cierto), que se ve así:comportamiento de los valores predeterminados inconsistentes (NSUserDefaults) en los valores predeterminados del simulador de iPhone

 
(void) updateDefaults 
{ 
    NSMutableArray *spells = [[NSMutableArray alloc] init]; 
    NSMutableArray *locs = [[NSMutableArray alloc] init]; 

    for (DragView *dv in [boardView subviews]) 
    { 
     [spells addObject:[dv whichSpell]]; 
     [locs addObject:NSStringFromCGRect([dv frame])]; 
    } 

    [[NSUserDefaults standardUserDefaults] setObject:spells forKey:@"spells"]; 
    [[NSUserDefaults standardUserDefaults] setObject:locs forKey:@"locs"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 

    [spells release]; 
    [locs release]; 
} 

Los valores se guardan, a veces ... y restaurados, a veces. No puedo obtener una cuenta exacta sobre lo que hace o no funciona.

¿Alguien más tiene alguna experiencia similar? ¿Alguna sugerencia sobre qué podría hacer que funcione? El método de sincronización es la mejor manera de forzar la escritura de un disco y hacer que los valores se guarden, o hay algo mejor (tanto para la producción como para el simulador).

Gracias Ryan

Respuesta

2

Debe utilizar un NSKeyedArchiver para guardar sus matrices, tales como:

[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:spells] forKey:@"spells"]; 
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:locs] forKey:@"locs"]; 
[[NSUserDefaults standardUserDefaults] synchronize]; 

También debe asegurarse de que su clase de hechizos implementa el protocolo NSCoding (encodeWithCoder: y initWithCoder:), si es una clase personalizada. Parece que tus locs son NSStrings, que se archivarán muy bien.

También tendrá que hacer algo como

NSData *dataRepresentingSavedSpells = [currentDefaults objectForKey:@"spells"]; 
if (dataRepresentingSavedSpells != nil) 
{ 
    NSArray *oldSpells = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedSpells]; 
} 

Para cargar los valores antiguos de los valores predeterminados.

Uso la sincronización para escribir en el disco al salir, y ha sido muy confiable en mi experiencia.

+0

Ok, gracias. Estoy ligeramente confundido en cuanto a por qué tengo que usar un NSKeyedArchiver para almacenar una matriz ... ¿el setObject estándar no funcionará de manera precisa o suficiente por alguna razón? No me había encontrado con NSKeyedArchiver antes, así que no estoy familiarizado con más que el párrafo de introducción de los documentos. –

+0

Creo que debe usarlo para asegurarse de que sus clases personalizadas compatibles con NSCoding estén archivadas correctamente. Creo que setObject solo funciona con matrices de objetos compatibles. Sin embargo, podría estar equivocado. –

2

En Mac OS X, y probablemente también en iPhone OS, la base de datos predeterminada solo puede contener objetos de lista de propiedades: NSString, NSNumber, NSArray, NSDictionary y NSData.

No está claro desde el fragmento de código qué tipo es un hechizo, pero si no es uno de los anteriores, no se almacenará en la base de datos predeterminada. Sus opciones son:

  1. Escriba un método que convierta su objeto ay desde una representación plist. En otras palabras, un método para crear un NSDictionary a partir de su objeto y otro método para inicializar el objeto utilizando un NSDictionary. También puede elegir almacenarlo como NSArray o NSString.
  2. Haga que su objeto implemente el protocolo NSCoding y luego use NSKeyedArchiver para convertir el objeto a un objeto NSData, y NSKeyedUnarchiver para convertirlo de nuevo.
+0

Sí, en algún momento me di cuenta de que mi clase personalizada no era compatible, y me he ido con una versión de su opción n. ° 1. Tengo una representación de cadena canónica del objeto Spell, que utilizo para recrear dinámicamente el objeto en carga. más adelante, tendré que ir por la ruta de la opción # 2, pero todavía no. –

Cuestiones relacionadas