Necesito crear NSManagedObject
instancias, hacer algunas cosas con ellas y luego tirarlas a la basura o almacenarlas en sqlite db. El problema es que no puedo crear instancias NSManagedObject
sin conexión a NSManagedObjectContext
y esto significa que tengo que aclarar de alguna manera después de decidir que no necesito algunos de los objetos en mi base de datos.
Para lidiar con eso, he creado un almacén en memoria usando el mismo coordinador y estoy colocando objetos temporales allí usando assignObject:toPersistentStore.
Ahora, ¿cómo me aseguro de que estos objetos temporales no lleguen a los datos, que obtengo del común al contexto de ambas tiendas? ¿O tengo que crear contextos separados para tal tarea?
UPD:
Ahora estoy pensando en crear un contexto separado para el almacenamiento en memoria. ¿Cómo muevo objetos de un contexto a otro? ¿Solo usa [insertObject de contexto:]? ¿Funcionará bien en esta configuración? Si inserto un objeto del gráfico de objetos, ¿el gráfico completo también se inserta en el contexto?
fuente
Respuestas:
NOTA: Esta respuesta es muy antigua. Consulte los comentarios para ver el historial completo. Desde entonces, mi recomendación ha cambiado y ya no recomiendo usar
NSManagedObject
instancias no asociadas . Mi recomendación actual es utilizarNSManagedObjectContext
instancias secundarias temporales .Respuesta original
La forma más sencilla de hacer esto es crear sus
NSManagedObject
instancias sin un asociadoNSManagedObjectContext
.NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC]; NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
Luego, cuando quieras guardarlo:
[myMOC insertObject:unassociatedObject]; NSError *error = nil; if (![myMoc save:&error]) { //Respond to the error }
fuente
iOS5 ofrece una alternativa más sencilla a la respuesta de Mike Weller. En su lugar, utilice un NSManagedObjectContext secundario . Elimina la necesidad de trampolín a través de NSNotificationCenter
Para crear un contexto secundario:
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; childContext.parentContext = myMangedObjectContext;
Luego crea tus objetos usando el contexto secundario:
NSManagedObject *o = [NSEntityDescription insertNewObjectForEntityForName:@"MyObject" inManagedObjectContext:childContext];
Los cambios solo se aplican cuando se guarda el contexto secundario. Entonces, para descartar los cambios, simplemente no guarde.
Todavía hay una limitación en las relaciones. es decir, no puede crear relaciones con objetos en otros contextos. Para sortear esto, use objectID's, para obtener el objeto del contexto secundario. p.ej.
NSManagedObjectID *mid = [myManagedObject objectID]; MyManagedObject *mySafeManagedObject = [childContext objectWithID:mid]; object.relationship=mySafeManagedObject;
Tenga en cuenta que guardar el contexto secundario aplica los cambios al contexto principal. Guardar el contexto principal persiste los cambios.
Consulte la sesión 214 de la wwdc 2012 para obtener una explicación completa.
fuente
moc
en el tercer fragmento? EschildContext
omyMangedObjectContext
?NSManagedObject
ya proporciona lo relevanteNSManagedObjectContext
, puede automatizar la elección del contexto:NSManagedObject* objectRelatedContextually = [objectWithRelationship.managedObjectContext objectWithID:objectRelated.objectID];
y luegoobjectWithRelationship.relationship = objectRelatedContextually;
.La forma correcta de lograr este tipo de cosas es con un nuevo contexto de objeto administrado. Creas un contexto de objeto administrado con el mismo almacén persistente:
NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease]; [tempContext setPersistentStore:[originalContext persistentStore]];
Luego agrega nuevos objetos, los muta, etc.
Cuando llega el momento de guardar, debe llamar a [tempContext save: ...] en tempContext, y manejar la notificación de guardar para fusionarla en su contexto original. Para descartar los objetos, simplemente suelte este contexto temporal y olvídese de él.
Entonces, cuando guarda el contexto temporal, los cambios se conservan en la tienda y solo necesita recuperar esos cambios en su contexto principal:
/* Called when the temp context is saved */ - (void)tempContextSaved:(NSNotification *)notification { /* Merge the changes into the original managed object context */ [originalContext mergeChangesFromContextDidSaveNotification:notification]; } // Here's where we do the save itself // Add the notification handler [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tempContextSaved:) name:NSManagedObjectContextDidSaveNotification object:tempContext]; // Save [tempContext save:NULL]; // Remove the handler again [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:tempContext];
Esta es también la forma en que debe manejar las operaciones de datos centrales de subprocesos múltiples. Un contexto por hilo.
Si necesita acceder a objetos existentes desde este contexto temporal (para agregar relaciones, etc.), entonces debe usar la ID del objeto para obtener una nueva instancia como esta:
NSManagedObject *objectInOriginalContext = ...; NSManagedObject *objectInTemporaryContext = [tempContext objectWithID:[objectInOriginalContext objectID]];
Si intenta utilizar un
NSManagedObject
en el contexto incorrecto, obtendrá excepciones al guardar.fuente
NSManagedObjectContext
es costoso tanto en memoria como en CPU. Me doy cuenta de que esto estaba originalmente en algunos de los ejemplos de Apple, pero han actualizado y corregido esos ejemplos.La creación de objetos temporales a partir de un contexto nulo funciona bien hasta que intentas tener una relación con un objeto cuyo contexto! = Nulo!
asegúrese de que está de acuerdo con eso.
fuente
Lo que estás describiendo es exactamente para qué
NSManagedObjectContext
sirve.De la guía de programación de datos básicos: conceptos básicos de datos básicos
Y guía de programación de datos básicos: validación de objetos administrados
NSManagedObjectContext
Los s están diseñados para ser livianos. Puede crearlos y descartarlos a voluntad: es el coordinador de tiendas persistentes y sus dependencias son "pesadas". Un único coordinador de tienda persistente puede tener muchos contextos asociados. Según el modelo de confinamiento de subprocesos obsoleto y antiguo, esto significaría establecer el mismo coordinador de tienda persistente en cada contexto. Hoy en día, significaría conectar contextos anidados a un contexto raíz que está asociado con el coordinador de tienda persistente.Cree un contexto, cree y modifique objetos gestionados dentro de ese contexto. Si desea conservarlos y comunicar esos cambios, guarde el contexto. De lo contrario, deséchelo.
Intentar crear objetos gestionados independientemente de un
NSManagedObjectContext
es buscar problemas. Recuerde que Core Data es, en última instancia, un mecanismo de seguimiento de cambios para un gráfico de objetos. Debido a esto, los objetos gestionados son realmente parte del contexto del objeto gestionado . El contexto observa su ciclo de vida y, sin el contexto, no todas las funciones del objeto gestionado funcionarán correctamente.fuente
Dependiendo de su uso del objeto temporal, existen algunas advertencias a las recomendaciones anteriores. Mi caso de uso es que quiero crear un objeto temporal y vincularlo a las vistas. Cuando el usuario opta por guardar este objeto, quiero configurar relaciones con los objetos existentes y guardar. Quiero hacer esto para evitar crear un objeto temporal que contenga esos valores. (Sí, podría esperar hasta que el usuario guarde y luego tomar el contenido de la vista, pero estoy colocando estas vistas dentro de una tabla y la lógica para hacer esto es menos elegante).
Las opciones para objetos temporales son:
1) (Preferido) Cree el objeto temporal en un contexto secundario. Esto no funcionará porque estoy vinculando el objeto a la interfaz de usuario y no puedo garantizar que los descriptores de acceso al objeto se llamen en el contexto secundario. (No he encontrado documentación que indique lo contrario, así que debo asumir).
2) Cree el objeto temporal con un contexto de objeto nulo. Esto no funciona y da como resultado la pérdida / corrupción de datos.
Mi solución: Resolví esto creando el objeto temporal con un contexto de objeto nulo, pero cuando guardo el objeto, en lugar de insertarlo como # 2, copio todos sus atributos en un nuevo objeto que creo en el contexto principal. Creé un método de apoyo en mi subclase NSManagedObject llamado cloneInto: que me permite copiar atributos y relaciones fácilmente para cualquier objeto.
fuente
Para mí, la respuesta de Marcus no funcionó. Esto es lo que funcionó para mí:
NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC]; NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
entonces, si decido guardarlo:
[myMOC insertObject:unassociatedObjet]; NSError *error = nil; [myMoc save:&error]; //Check the error!
Tampoco debemos olvidar liberarlo.
fuente
Estoy reescribiendo esta respuesta para Swift como todas las preguntas similares para una redirección rápida a esta pregunta.
Puede declarar el objeto sin ningún ManagedContext utilizando el siguiente código.
let entity = NSEntityDescription.entity(forEntityName: "EntityName", in: myContext) let unassociatedObject = NSManagedObject.init(entity: entity!, insertInto: nil)
Posteriormente, para guardar el objeto puede insertarlo en el contexto y guardarlo.
myContext.insert(unassociatedObject) // Saving the object do { try self.stack.saveContext() } catch { print("save unsuccessful") } }
fuente