puedo operador nuevo mini descargar correspondiente configuraciĆ³n como ajustes actualizar ios core-data nsfetchedresultscontroller nsmanagedobjectcontext nsoperationqueue

ios - operador - NSFetchedResultsController no muestra actualizaciones desde un contexto diferente



ios 12 (2)

Solo tuve el mismo problema, que resolví con contextos de padres / hijos. Este es el problema que tuve.

Estaba actualizando mi gráfico de objetos de Core Data en un hilo de fondo que tenía su propio managedObjectContext (que es obligatorio), y mi fetchedResultsController no pudo recoger los cambios realizados en la base de datos.

Después de que lo resolví, tomé algunas notas:

ManagedObjectContext s no es seguro para subprocesos, lo que significa que managedObjectContext no se puede compartir con otros subprocesos. Si un hilo necesita usar un managedObjectContext , entonces inicializará su propio managedObjectContext.

Para inicializar managedObjectContext hay dos formas:

  • alloc/init luego establece su propiedad persistentStoreCoordinator

  • alloc/init establece luego una propiedad parentContext lugar de una propiedad persistentStoreCoordinator

nota: uno no puede establecer tanto la propiedad persistentStoreCoordinator como la propiedad parentContext de un managedObjectContext .

El uso de contextos padre / hijo es necesario cuando el contexto se ejecuta en una secuencia de fondo que está "vinculada a controladores y objetos de interfaz de usuario que deben utilizarse solo en el hilo principal" (documentación de datos básicos).

Estos son los requisitos necesarios para los contextos padre / hijo:

  • el contexto principal vive en el hilo principal

  • el contexto del niño vive en el hilo de fondo

  • ambos contextos deben inicializarse con un método initWithConcurrencyType:NSMainQueueConcurrencyType .

  • cuando el lote de cambios se ha realizado en el contexto secundario, ambos contextos deben realizar una operación de salvar. Estas operaciones de salvar deben estar anidadas en los métodos performBlock, es decir:

    childContext performBlock:^{ [childContext save:nil]; [self.parentContext performBlock:^{ [self.parentContext save:nil]; }]; }];

EDITAR: El código anterior es en realidad una mala idea por 2 razones:

1) Funciona sin guardar el contexto principal.

2) El hilo principal está bloqueado si el contexto principal se ejecuta en él.

¡Espero que haya sido de ayuda!

EDITAR: Aquí hay un hilo de StackOverflow que me ayudó mucho: ¿necesita un ManagedObjectContext principal de Core Data compartir un tipo de concurrencia con el contexto hijo?

Tengo un NSFetchedResultsController y unas pocas operaciones actualizan los objetos administrados en hilos separados a través de NSOperationQueue .

El FRC (con su predicado) se ve así:

- (NSFetchedResultsController*)fetchedResultsController { if(fetchedResultsController) return fetchedResultsController; NSManagedObjectContext* mainContext = [self managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; [fetchRequest setEntity:[NSEntityDescription entityForName:@"Check" inManagedObjectContext:mainContext]]; [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"isSync == %@", [NSNumber numberWithBool:NO]]]; [fetchRequest setFetchBatchSize:10]; fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil]; fetchedResultsController.delegate = self; [fetchRequest release], fetchRequest = nil; return fetchedResultsController; }

El hilo principal y la operación roscada tienen sus propios contextos de objetos gestionados. Solo comparten el mismo coordinador.

Dentro de la operación con hilos, cambio la propiedad isSync de NO a YES . Para saber qué es la entidad Check para actualizar, el contexto principal pasa al elemento con subprocesos un NSManagedObjectID . La operación con hebra recupera el objeto administrado de la siguiente manera:

-(void)main { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSManagedObjectContext *exportContext = [[NSManagedObjectContext alloc] init]; [exportContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]]; //... Check* check = (Check*)[exportContext existingObjectWithID:objID error:&error]; check.isSync = [NSNumber numberWithBool:YES]; //... [exportContext save:&error]; [pool release], pool = nil; }

Cuando la operación de subproceso llama a save llama a la notificación mergeChangesFromContextDidSaveNotification y el contexto principal combina los cambios.

- (void)contextChanged:(NSNotification*)notification { if ([notification object] == [self managedObjectContext]) return; if (![NSThread isMainThread]) { [self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES]; return; } [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification]; }

El registro de la descripción de la notification lleva a verificar que los cambios se realicen correctamente.

Mi problema

Los métodos delegados de NSFetchedResultsControllerDelegate no son invocados.

Esto es bastante extraño ya que tratar con el mismo contexto, el principal, permite escuchar los cambios y se llaman los métodos de delegados, por ejemplo, eliminar un objeto de fila en UITableView .

He encontrado algunos temas sobre SO con el mismo problema. He intentado todas las soluciones pero no puedo encontrar una solución valiosa:

  1. NSFetchedResultsController que no muestra actualizaciones de otros contextos

  2. NSFetchedResultsController no dispara el método de delegado después de fusionar la actualización desde el hilo de fondo

  3. NSFetchedResultsController with predicate ignora los cambios fusionados de NSManagedObjectContext diferente

Gracias de antemano.

Editar

El código anterior funcionaba en un modelo anterior. Luego creé un nuevo modelo para copiar (y pegar) entidades del anterior y ahora ya no funciona.

Sugerencias?

Editar 2

Este es el predicado que estoy usando en NSFetchedResultsController getter. Es mi culpa, pero cuando escribí la publicación no la copié.

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"insertionDate" ascending:NO]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; // previous code here [fetchRequest setSortDescriptors:sortDescriptors];

Ahora, sobre Jody último comentario

En la parte principal () de su NSOperation, está cargando nuevos objetos, y allí parece que está configurando isSync en YES para cada nuevo objeto. El predicado que utiliza para fetchedResultsController busca solo objetos que tengan isSync == NO.

Supongo que cuando la propiedad isSync se establece en SÍ, NSFetchedResultsController observa que los cambios y elimina las filas que no coinciden con el predicado. ¿Me equivoco?

Recuerde que al fusionar los cambios del fondo al hilo principal, puedo ver que pocos objetos han actualizado su propiedad isSync .


Tienes la idea básica, por lo que probablemente haya un error en algún lugar de tu código ...

Verifique que se está registrando correctamente para recibir la notificación del MOC de fondo.

Regístrese para recibir todas las notificaciones de todos los objetos. En ese método, registre el evento y todos sus datos. Cuando el objeto es un MOC, vacíe todas sus propiedades (especialmente las listas de objetos registrados, insertados, actualizados y eliminados).

Coloque una declaración de registro justo antes y después de la llamada guardada, y en el controlador de notificación para fusionar la notificación.

Además, omitiste muchos códigos, por lo que es difícil saber lo que realmente estás haciendo, pero el ejemplo del código que incluiste parece que es una configuración difícil. Sincroniza con SÍ para todos los objetos que se cargan, pero tu solicitud de búsqueda solo quiere aquellos con el conjunto isSync. a NO. Ninguno de esos objetos nuevos pasará ese predicado.

Finalmente, verifique dos veces la definición de su modelo y asegúrese de estar usando el tipo de número correcto. Esto puede ser una gran fuente de problemas.

EDITAR

Oh, sí, lo olvidé ... tu solicitud de búsqueda no tiene un descriptor de ordenación. Cuando crea un FRC, su solicitud de búsqueda debe contener al menos un descriptor de clasificación ... si tiene varias secciones, el primer descriptor de clasificación se usa para agrupar los objetos en secciones.

Para seguir con el comentario de Alexsander ... Aludí al principio de mi publicación, pero ciertamente no quieres escuchar las notificaciones de un MOC a menos que sea bien conocido como uno de los tuyos (a menos, por supuesto, que seas simplemente registrando para propósitos de depuración). Debes saber sobre el MOC que estás usando.

Además, sugeriría usar MOC padre / hijo para este tipo de procesamiento, pero lo que está haciendo debería funcionar si se hace correctamente.

Principal (tipo de concurrencia privada) Principal (tipo de concurrencia principal)

Luego, con sus MOC de fondo, solo pídales que configuren el moc principal como su padre. Cuando guardan, sus objetos se inyectan directamente en el MOC principal. El MOC principal puede entonces emite rescates en tiempos posteriores para ponerlos en el disco.

O bien, puede convertir su MOC de fondo en "padre" y luego el MOC "principal" puede volver a emitir la recuperación para obtener los datos del padre.