Existe una regla de oro cuando se trata de Datos centrales: un contexto de objeto administrado por subproceso. Los contextos de objeto administrado no son seguros para subprocesos, por lo que si está trabajando en una tarea en segundo plano, utilice el hilo principal para evitar conflictos con operaciones de interfaz de usuario o cree un contexto nuevo para realizar el trabajo. Si el trabajo va a tomar unos segundos luego debe hacer esto último para evitar que su UI se bloquee.
Para ello se crea un nuevo contexto y darle el mismo almacén persistente como su marco principal:
NSManagedObjectContext *backgroundContext = [[[NSManagedObjectContext alloc] init] autorelease];
[backgroundContext setPersistentStoreCoordinator:[mainContext persistentStoreCoordinator]];
realizar operaciones lo que tenga que hacer, a continuación, cuando se guarda este nuevo contexto que necesita para manejar la notificación de guardar y fusionar los cambios en su contexto principal con el mensaje mergeChangesFromContextDidSaveNotification:
. El código debería ser algo como esto:
/* Save notification handler for the background context */
- (void)backgroundContextDidSave:(NSNotification *)notification {
/* Make sure we're on the main thread when updating the main context */
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
withObject:notification
waitUntilDone:NO];
return;
}
/* merge in the changes to the main context */
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}
/* ... */
/* Save the background context and handle the save notification */
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:backgroundContext];
[backgroundContext save:NULL];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:syncContext];
manipulación del aviso guardar y fusión es importante de lo contrario su principal UI/contexto no verá los cambios realizados. Al fusionarse, su fetchResultsController principal obtendrá eventos de cambio y actualizará su UI como era de esperar.
Otra cosa importante a tener en cuenta es que las instancias de NSManagedObject solo se pueden usar en el contexto desde el que se obtuvieron. Si su operación necesita una referencia a un objeto, debe pasar el objeto objectID
a la operación y recuperar una instancia de NSManagedObject del nuevo contexto usando existingObjectWithID:
. Así que algo como:
/* This can only be used in operations on the main context */
MyNSManagedObject *objectInMainContext =
[self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
/* This can now be used in your background context */
MyNSManagedObject *objectInBackgroundContext =
(MyNSManagedObject *) [backgroundContext existingObjectWithID:[objectInMainContext objectID]];
Entonces, lo que usted dice es que en mi caso, en lugar de usar fetchedResultsController, debería crear un nuevo contexto de objeto administrado (backgro undManagedObjectContext), busque el objeto gestionado requerido, realice las operaciones requeridas, actualice el objeto gestionado, guarde este contexto de objeto gestionado (backgroundManagedObjectContext) y fusione los cambios para reflejarlos en el contexto principal del objeto gestionado. Esto hará que mi vida sea bastante maldita miserable. – Mustafa
Aún puede usar el controlador de resultados obtenidos para mostrar y actualizar cosas en su UI. El código que te he mostrado es todo lo que se requiere para realizar cualquier operación que necesites en un contexto separado, nada más debería cambiar. –
Hay formas de evitar esta regla de oro: https://github.com/adam-roth/coredata-threadsafe. – aroth