2009-02-01 19 views
17

Imagine una entidad CoreData (por ejemplo, llamada searchEngine).
NSManagedObjectContext gestiona algunas "instancias" de esta entidad.
El usuario final podrá seleccionar su "standard searchEngine" con un NSPopupButton.
El selected object de NSPopupButton debe vincularse a NSUserDefaults.
El problema:Guardar entidades de datos centrales en NSUserDefaults

1) @try {} ahorrar

a) Si intenta guardar el modo de "ejemplo" directamente a NSUserDefaults llega algo como esto:

-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value ' (entity: searchEngine; id: 0x156f60 ; data: { 
    url = " http://google.de/ "; 
    someAttribute = 1; 
    name = "google"; 
})' of class 'searchEngine'.

b) Si intenta convertir la "instancia" a NSData viene esto:

-[searchEngine encodeWithCoder:]: unrecognized selector sent to instance 0x1a25b0

So ¿Alguna idea de cómo obtener estas entidades en una información compatible con plist?

2) @try {} registerDefaults

Por lo general, el método se implementa en registerDefaults:+ (void)initialize. El problema aquí es que se llama a este método antes de que CoreData cargue las entidades guardadas de su base de datos. Entonces no puedo establecer un valor predeterminado para un objeto que no existe, ¿verdad?

sé, preguntas largas ... pero: try {[me dan detalles]}; D

Respuesta

6

Usted no quiere tratar de archivar una entidad de datos central y almacenarla. En su lugar, debe almacenar la clave o algún otro atributo conocido y usarlo para recuperar la entidad cuando se inicia la aplicación.

un código de ejemplo (ligeramente modificada del ejemplo publicado en el Core Data Programming Guide):

NSManagedObjectContext *moc = [self managedObjectContext]; 
NSEntityDescription *entityDescription = [NSEntityDescription 
    entityForName:@"SearchEngine" inManagedObjectContext:moc]; 
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; 
[request setEntity:entityDescription]; 

NSPredicate *predicate = [NSPredicate predicateWithFormat: 
    @"engineName LIKE[c] '%@'", selectedEngineName]; 
[request setPredicate:predicate]; 

NSError *error = nil; 
NSArray *array = [moc executeFetchRequest:request error:&error]; 
if (array == nil) 
{ 
    // Deal with error... 
} 

De esta manera se guarda el nombre en los valores predeterminados de usuario a buscar a la entidad cuando sea necesario.

+0

Mmh. ¿Sabes por qué 'array! = Nil' pero' [array count] <0' ... no quiere funcionar ... – papr

+0

If array! = Nil, entonces no hay ningún error pero tampoco puede haber registros returned ([array count] == ​​0) ... sin embargo, [array count] <0 can * never * puede ocurrir ya que el mensaje de recuento devuelve un tipo NSUInteger. Es muy probable que el compilador elimine cualquier prueba de este tipo ([array count] <0). –

+0

Sí. Quise decir ([array count] == ​​0). Lo siento por eso. Solo quería expresar que no hay nada en este conjunto. ;) – papr

33

Si necesita almacenar una referencia a un objeto administrado específico, utilice la representación URI de su ID de objeto gestionado:

NSURL *moIDURL = [[myManagedObject objectID] URIRepresentation]; 

continuación, puede guardar la URL a los valores predeterminados de usuario.

Para recuperar el objeto gestionado, que utilice:

NSManagedObjectID *moID = [myPersistentStoreCoordinator managedObjectIDForURIRepresentation:moIDURL]; 
NSManagedObject *myManagedObject = [myContext objectWithID:moID]; 

La única salvedad es que debe asegurarse de que el ID de objeto gestionado original es permanente - esto no es un problema si ya ha guardado el objeto, alternativamente puede usar obtainPermanentIDsForObjects:error:.

+3

Creo que esta es una buena solución. Una pequeña adición, como dice la documentación de NSUserDefaults, es necesario que archive objetos NSURL como NSData. Así que cuidado de no salvar a NSURL tal como es. Acabo de cometer este error y no conseguí nada cuando intenté recuperar el objeto. Tenga en cuenta también que NSUserDefaults tiene un método setURL: forKey :. No creo que esto esté disponible para iPhone OS en este momento. – tilish

+7

setURL: forKey: está disponible en iOS 4.0 y posterior – djskinner

+1

¡TEN EN CUENTA! El comentario de tilish es importante, la solución correcta está aquí: http://stackoverflow.com/a/516735/1780492 Sin esto, aparecerá un mensaje de error: "intento de insertar un objeto de lista no-propiedad x-coredata:" – BootMaker

6

Aquí está la manera más limpia y más corta de hacer esto actualmente usando los métodos setURL y getURL agregados en 4.0 para evitar llamadas adicionales a NSKeyedUnarchiver y NSKeyedArchiver:

Setter:

+ (void)storeSomeObjectId:(NSManagedObjectID *)objectId 
{ 
    [[NSUserDefaults standardUserDefaults] setURL:[objectId URIRepresentation] 
              forKey:@"someObjectIdKey"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
} 

Getter:

+ (SomeManagedObject *)getObjectByStoredId 
{ 
    NSURL *uri = [[NSUserDefaults standardUserDefaults] URLForKey:@"someObjectIdKey"]; 
    NSManagedObjectID *objectId = [self.persistentStoreCoordinator managedObjectIDForURIRepresentation:uri]; 
    SomeManagedObject *object = [self.managedObjectContext objectWithID:objectId]; 
} 
Cuestiones relacionadas