¿Cómo comparto un almacén de Core Data entre procesos usando NSDistributedNotifications?

Fondo

Ya he publicado una pregunta sobre los conceptos básicos decompartiendo un almacén de Datos Core entre procesos.

Estoy tratando de implementar las recomendaciones dadas y estoy teniendo problemas.

Mi meta

Tengo dos procesos: la aplicación de ayuda y la interfaz de usuario. Ambos comparten un único almacén de datos. Quiero que la interfaz de usuario actualice su NSManagedObjectContext cuando la aplicación Helper haya guardado nuevos datos en la tienda.

Flujo actual del programa

El proceso de la aplicación de ayuda escribe datos en la tienda.

En la aplicación de ayuda, escucho las notificaciones de NSManagedObjectContextDidSaveNotification.

Cuando se guarda el contexto, codifico los objetos insertados, eliminados y actualizados utilizando sus representaciones URI y NSArchiver.

Envío una NSNotification al NSDistributedNotificationCenter con este diccionario codificado como el userInfo.

El proceso de IU está escuchando la notificación de guardar. Cuando recibe la notificación, desarchiva la información de usuario usando NSUnarchiver.

Busca todos los objetos actualizados / insertados / eliminados de los URI dados y los reemplaza con NSManagedObjects.

Construye una NSNotification con los objetos actualizados / insertados / eliminados.

Llamo a mergeChangesFromContextDidSaveNotification: en el contexto de objeto gestionado del proceso de UI, pasando la NSNotification que construí en el paso anterior.

El problema

Los objetos insertados tienen fallas en la multa del Contexto de objeto administrado de la interfaz de usuario y aparecen en la interfaz de usuario. El problema viene con los objetos actualizados. Simplemente no se actualizan.

Lo que he intentado

Lo más obvio es intentar pasar la Notificación de guardado del proceso de la aplicación de ayuda al proceso de la interfaz de usuario. Fácil, ¿verdad? Bueno no. Las notificaciones distribuidas no me permitirán hacerlo ya que el diccionario de información del usuario no está en el formato correcto. Es por eso que estoy haciendo todas las cosas de NSArchiving.

He intentado llamar a refreshObject: mergeChanges: YES en NSManagedObjects para actualizarse, pero esto no parece tener ningún efecto.

He intentado realizar el mergeChangesFromContextDidSaveNotification: selector en el hilo principal y el hilo actual. Tampoco parece afectar el resultado.

He intentado usar mergeChangesFromContextDidSaveNotification: antes entre subprocesos, que por supuesto es mucho más simple y funcionó perfectamente. Pero necesito esta misma funcionalidad entre procesos.

¿Alternativas?

¿Me estoy perdiendo de algo? Siempre tengo la sensación de que estoy haciendo esto mucho más complejo de lo que debe ser, pero después de leer la documentación varias veces y pasar unos días sólidos en esto, no veo otra forma de actualizar el MOC de la interfaz de usuario.

¿Hay una forma más elegante de hacer esto? ¿O simplemente estoy cometiendo un error tonto en algún lugar de mi código?

El código

He intentado hacerlo lo más legible posible, pero sigue siendo un desastre. Lo siento.

Código de aplicación de ayuda

   -(void)workerThreadObjectContextDidSave:(NSNotification *)saveNotification {
        NSMutableDictionary *savedObjectsEncodedURIs = [NSMutableDictionary dictionary];
        NSArray *savedObjectKeys = [[saveNotification userInfo] allKeys];

        for(NSString *thisSavedObjectKey in savedObjectKeys) {
            // This is the set of updated/inserted/deleted NSManagedObjects.
            NSSet *thisSavedObjectSet = [[saveNotification userInfo] objectForKey:thisSavedObjectKey];
            NSMutableSet *thisSavedObjectSetEncoded = [NSMutableSet set];

            for(id thisSavedObject in [thisSavedObjectSet allObjects]) {
                // Construct a set of URIs that will be encoded as NSData
                NSURL *thisSavedObjectURI = [[(NSManagedObject *)thisSavedObject objectID] URIRepresentation];
                [thisSavedObjectSetEncoded addObject:thisSavedObjectURI];
            }
            // Archive the set of URIs.
            [savedObjectsEncodedURIs setObject:[NSArchiver archivedDataWithRootObject:thisSavedObjectSetEncoded] forKey:thisSavedObjectKey];
        }

        if ([[savedObjectsEncodedURIs allValues] count] > 0) {
            // Tell UI process there are new objects that need merging into it's MOC
            [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.synapticmishap.lapsus.save" object:@"HelperApp" userInfo:(NSDictionary *)savedObjectsEncodedURIs];
        }
    }

Código UI

-(void)mergeSavesIntoMOC:(NSNotification *)notification {
    NSDictionary        *objectsToRefresh        = [notification userInfo];
    NSMutableDictionary *notificationUserInfo    = [NSMutableDictionary dictionary];
    NSArray *savedObjectKeys = [[notification userInfo] allKeys];

    for(NSString *thisSavedObjectKey in savedObjectKeys) {
        // Iterate through all the URIs in the decoded set. For each URI, get the NSManagedObject and add it to a set.
        NSSet *thisSavedObjectSetDecoded = [NSUnarchiver unarchiveObjectWithData:[[notification userInfo] objectForKey:thisSavedObjectKey]];
        NSMutableSet *savedManagedObjectSet = [NSMutableSet set];

        for(NSURL *thisSavedObjectURI in thisSavedObjectSetDecoded) {
            NSManagedObject *thisSavedManagedObject = [managedObjectContext objectWithID:[persistentStoreCoordinator managedObjectIDForURIRepresentation:thisSavedObjectURI]];
            [savedManagedObjectSet addObject:thisSavedManagedObject];
            // If the object is to be updated, refresh the object and merge in changes.
            // This doesn't work!
            if ([thisSavedObjectKey isEqualToString:NSUpdatedObjectsKey]) {
                [managedObjectContext refreshObject:thisSavedManagedObject mergeChanges:YES];
                [managedObjectContext save:nil];
            }
        }
        [notificationUserInfo setObject:savedManagedObjectSet forKey:thisSavedObjectKey];
    }
    // Build a notification suitable for merging changes into MOC.
    NSNotification *saveNotification = [NSNotification notificationWithName:@"" object:nil userInfo:(NSDictionary *)notificationUserInfo];
    [managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                                    withObject:saveNotification
                                 waitUntilDone:YES];
}

Respuestas a la pregunta(6)

Su respuesta a la pregunta