45

Tengo una interfaz de usuario para insertar una transacción. una vez que el usuario hace clic en un signo más, obtiene la pantalla y quiero crear una instancia de mi entidad NSDA de datos básicos que permite al usuario trabajar en ella. Luego, cuando el usuario haga clic en el botón Guardar, llamaré a la función de guardar.¿Hay alguna forma de instanciar un NSManagedObject sin insertarlo?

tan abajo al código:

transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext]; 
//even if i dont call save: its going to show up on my table 
[self.managedObjectContext save:&error] 

P.S Estoy utilizando un NSFetchedResultsController en esa mesa y veo que la NSFetchedResultsController es la inserción de una sección y un objeto a la mesa.

Mi idea es si hay una manera de instanciar la Transacción NSManagedObject podría actualizarlo sin guardar hasta que el cliente elija.

Respuesta

16

Existe un problema fundamental con el uso de un MOC nulo: se supone que los objetos en MOC diferentes no se refieren entre sí. — esto también se aplica cuando un lado de una relación tiene un MOC nulo. ¿Qué pasa si guardas? (¿Qué sucede cuando se guarda otra parte de la aplicación?)

Si su objeto no tiene relaciones, entonces hay muchas cosas que puede hacer (como NSCoding).

Es posible que pueda usar -[NSManagedObject isInserted] en NSPredicate (presumiblemente es SÍ entre insertar y guardar correctamente).Alternativamente, puede usar una propiedad transitoria con el mismo comportamiento (configúrelo en SÍ en despertar de Inserción y NO en voluntad de Salvar). Ambos pueden ser problemáticos si se guarda una parte diferente de tu aplicación.

Sin embargo, el uso de un segundo MOC es la forma en que "se supone" que CoreData se utilizará; maneja la detección y resolución de conflictos automáticamente. Por supuesto, no desea crear un nuevo MOC cada vez que haya un cambio; podría ser vagamente razonable tener un MOC para cambios no guardados por el "hilo de usuario" lento si no le importa que algunas partes de la UI vean cambios no guardados en otras partes (la sobrecarga de la comunicación entre MOC es insignificante).

+0

Hola @tc. Probé la primera respuesta que es insertarIntoManagedObjectContext: nil, pero cuando quise asignar una relación, la aplicación se bloqueó con un error: reason: 'Intento ilegal de establecer una relación' categoría 'entre objetos en diferentes contextos. así que supongo que mi pregunta es que, dado que no es legal establecer una relación entre un objeto NSManaged de contexto y un objeto gestionado fuera de contexto, ¿cuál sería la solución? –

+0

Terminé creando una entidad de categoría de la misma manera sin contexto, pero cuando se trataba de ahorrar, añadía tanto al contexto como luego funcionaba bien. –

+2

Puedo dar fe de la corrección de esta respuesta.Acabo de recibir un problema relacionado con tener el contexto nulo para un objeto. Los valores de atributo que se asignan al objeto antes de agregarlo a un contexto no se propagan al contexto primario cuando finalmente el objeto se agrega al contexto secundario. Los atributos se almacenan como 'nil' en el almacén de persistencia. Cuando cambié el orden (es decir, asignó valores de atributo después de insertarlo en un contexto), las cosas funcionaron correctamente. Moraleja de la historia es que no es una buena idea crear una instancia de un objeto sin un contexto. –

8

Puede insertar NSManagedObjectContext con -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:], pasando nil para el contexto del objeto gestionado. Debe, por supuesto, asignarlo a un contexto (utilizando -[NSManageObjectContext insertObject:] antes de guardar. Sin embargo, hasta donde yo sé, no es realmente el patrón previsto en los datos centrales (pero vea la respuesta de @mzarra here). Hay algunos pedidos complicados problemas (es decir, asegurarse de que la instancia se asigna a un contexto antes de que espere tener uno, etc.). El patrón más estándar es crear un nuevo contexto de objeto administrado e insertar su nuevo objeto en ese contexto. Cuando el usuario guarda, guarde el contexto, y maneja el NSManagedObjectDidSaveNotification para fusionar los cambios en el contexto 'principal' .Si el usuario cancela la transacción, simplemente destruyes el contexto y continúas con tu negocio.

+0

Creo que significa 'NSManagedObject', no' NSManagedObjectContext'. De cualquier manera, no parece que pueda cambiar el MOC, un NSManagedObject está asociado con —, puede confundirlo con '- [NSManagedObjectContext assignObject: toPersistentStore:]'. –

+0

@tc, gracias por la captura de errores. –

30

Por lo que vale, Marcus Zarra parece para promover el enfoque de contexto nil, afirmando que es costoso crear un nuevo contexto. Para obtener más detalles ls, vea this answer a una pregunta similar.

actualización

Actualmente estoy usando el enfoque de contexto nulo y he encontrado algo que podría ser de interés para otros. Para crear un objeto gestionado sin contexto, utilice el método initWithEntity:insertIntoManagedObjectContext: de NSManagedObject. Según la documentación de Apple para este método:

If context is not nil , this method invokes [context insertObject:self] (which causes awakeFromInsert to be invoked).

La implicación aquí es importante. El uso de un contexto nil al crear un objeto administrado evitará que se llame a insertObject: y por lo tanto se evitará que se llame a awakeFromInsert. En consecuencia, cualquier inicialización de objeto o configuración de valores de propiedad predeterminados realizados en awakeFromInsert no se realizará automáticamente cuando se utiliza un contexto nil.

En pocas palabras: cuando se utiliza un objeto administrado sin un contexto, awakeFromInsert no se llamará automáticamente y es posible que necesite un código adicional para compensar.

+0

Hola, esto funcionó por un tiempo hasta que traté de establecer una relación entre mi transacción y una categoría NSManagedObject. luego, la aplicación se bloqueó debido a eso. Hay alguna manera de evitarlo ? –

+0

Si necesita establecer relaciones, elegiría el enfoque de dos contextos. Como tc. señala que no se supone que los objetos en diferentes contextos se refieran entre sí. Por otro lado, podría posponer la configuración de esas relaciones hasta * después * de insertar el nuevo objeto no asociado en su contexto principal. –

17

aquí es cómo lo resolví:

En carga, donde sabemos que se trata de una nueva transacción, creé un fuera de contexto uno.

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext]; 
     transaction = (Transaction *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 

continuación, cuando se trataba de establecer una relación de buques que hice esto:

if(transaction.managedObjectContext == nil){ 
     NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:self.managedObjectContext]; 
     Category *category = (Category *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 
     category.title = ((Category *)obj).title; 
     transaction.category = category; 
     [category release]; 
    } 
    else { 
     transaction.category = (Category *)obj; 
    } 

y al final para salvar:

if (transaction.managedObjectContext == nil) { 
     [self.managedObjectContext insertObject:transaction.category]; 
     [self.managedObjectContext insertObject:transaction]; 
    } 
    //NSLog(@"\n saving transaction\n%@", self.transaction); 

    NSError *error; 
    if (![self.managedObjectContext save:&error]) { 
     // Update to handle the error appropriately. 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     exit(-1); // Fail 
    } 
+0

Me preguntaba si podría hacer ... transaction = (Transaction *) [NSEntityDescription insertNewObjectForEntityForName: @ "Transaction" inManagedObjectContext: context]; y luego transaction.managedObjectContext = nil; ¿Eso estaría mal? – yunas

2

Un NSManagedObject se pueden crear utilizando el cero como el contexto, pero si hay otros objetos NSManagedObjects a los que se debe vincular, se producirá un error. La forma en que lo hago Paso el contexto en la pantalla de destino y creo un NSManagedObject en esa pantalla. Haga que todos los cambios vinculen otros NSManagedObjects. Si el usuario toca el botón cancelar, elimino el NSManagedObject y guardo el contexto. Si el usuario toca el botón Guardar, actualizo los datos en NSManagedObject, lo guardo en el contexto y lo suelte. En la pantalla de fuente, actualizo la tabla con una recarga.

Al eliminar NSManagedObject en la pantalla de destino, se proporciona la hora del núcleo de datos para actualizar el archivo. Por lo general, este es tiempo suficiente para que no vea el cambio en la tabla vista. En la aplicación Calendario de iPhone tiene un retraso desde el momento en que lo guarda hasta el momento en que aparece en la vista de tabla. Esto podría considerarse una buena cosa desde el punto de vista de la interfaz de usuario que su usuario se centrará en la fila que acaba de agregar. Espero que esto ayude.

-3
transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:nil]; 

si el último parámetro es nulo, se devolverá un NSManagedObject sin guardar db

+0

Esto causará un error: *** Aplicación de finalización debido a una excepción no detectada 'NSInvalidArgumentException', razón: '+ entityForName: nil no es un parámetro legal de NSManagedObjectContext que busca el nombre de la entidad ... – c9s

Cuestiones relacionadas