2009-11-29 5 views
8

Antecedentes¿Cómo comparto un almacén de datos centrales entre procesos utilizando NSDistributedNotifications?

Ya hemos publicado una pregunta sobre los fundamentos de sharing a Core Data store between processes.

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

Mi meta

que tienen 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 datos nuevos en la tienda.

el flujo del programa actual

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

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

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

  4. envío un NSNotification a la NSDistributedNotificationCenter con este diccionario codificado como el userInfo.

  5. El proceso de IU está escuchando para guardar la notificación. Cuando recibe la notificación, desarchiva el userInfo utilizando NSUnarchiver.

  6. Se busca todos los objetos actualizados/insertadas/suprimidas de los URIs dados y los reemplaza con NSManagedObjects.

  7. construye un NSNotification con los objetos actualizados/insertadas/borrados.

  8. Llamo a mergeChangesFromContextDidSaveNotification: en el contexto del objeto gestionado del proceso UI, pasando NSNotification I construido en el paso anterior.

El problema

objetos insertados se criticaron en el interfaz de usuario de objeto gestionado bien Contexto y aparecen en la interfaz de usuario. El problema viene con los objetos actualizados. Simplemente no se actualizan.

Lo que he tratado

  1. Lo más obvio sería intentar sea para pasar el Notificación Guardar en el proceso de aplicación auxiliar al proceso interfaz de usuario. Fácil, ¿verdad? Bueno no. Notificaciones distribuido no permitirán que haga que a medida que el diccionario userInfo no está en la derecha formato. Es por eso que estoy haciendo todas las cosas de NSArchiving .

  2. He intentado llamar refreshObject: mergeChanges: SÍ a la los NSManagedObjects a ser actualizados, pero esto no parece tener ningún efecto .

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

  4. He intentado usar mergeChangesFromContextDidSaveNotification: antes entre los hilos, que de curso es mucho más simple y funcionó perfectamente . Pero necesito esta misma funcionalidad entre procesos.

¿Alternativas?

¿Falta algo aquí? Constantemente estoy sintiendo que estoy haciendo esto mucho más complejo de lo necesario, pero después de leer la documentación varias veces y pasar unos días seguidos sobre esto, no veo otra forma de actualizar el MOC de la interfaz de usuario.

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

El Código

he intentado que sea lo más legible posible, pero sigue siendo un desastre. Lo siento.

ayudante Código aplicación

-(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 de interfaz de usuario

-(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]; 
} 
+1

¿Hay algún motivo por el que intente utilizar la comunicación entre procesos en lugar de mirar el archivo de almacenamiento persistente para ver cuándo se actualiza? –

+0

No realmente. Pero si vi el archivo de la tienda, necesitaría refrescar el contexto del objeto administrado y la única manera que puedo encontrar para hacerlo es mediante el método mergeChangesFromContextDidSaveNotification :. Sospecho que me falta una forma muy obvia de refrescar el MOC sin depender de este método. –

+0

'for (id thisSavedObject en [thisSavedObjectSet allObjects])' podría escribirse como 'for (id thisSavedObject en thisSavedObjectSet)' – user102008

Respuesta

1

Usted está buscando - (void) refreshObject: mergeChanges objeto (NSManagedObject *): (BOOL) Me bandera creer.

Esto actualizará el objeto con la información en la tienda persistente, fusionando los cambios si lo desea.

+0

Lo he usado en mi código. Sin embargo, en la forma en que lo estoy usando, parece que no funciona. –

1

Me gustaría ir con la sugerencia de Mike y simplemente ver el archivo de la tienda para los cambios.

Aunque puede que no sea la más eficiente, he tenido éxito usando - [NSManagedObjectContext reset] de un segundo proceso cuando hay un cambio en una tienda. En mi caso, el código es bastante lineal — Todo lo que hago es ejecutar una solicitud de recuperación para algunos datos después de restablecer. No sé cómo funcionará esto con enlaces y una interfaz de usuario complicada, pero es posible que pueda publicar una notificación para actualizar manualmente las cosas si no se gestiona automáticamente.

1

Tuve el mismo problema con una aplicación de iPhone en la que he estado trabajando. En mi caso, la solución implicó establecer el intervalo de permanencia del contexto en algo adecuadamente infinitesimal (por ejemplo, 0,5 segundos).

0

Establecimiento de rangosIntervalo de trabajos de contexto de objetos gestionados. Mi caso implica múltiples hilos en vez de proceso.

2

que utiliza el método de

http://www.mlsite.net/blog/?p=518

continuación, cada objeto tiene un fallo correctamente, pero los fallos se ha podido recuperar en la memoria caché por lo que todavía no hay ninguna actualización

que tenía que hacer [moc stalenessInterval = 0] ;

Y finalmente funcionó, con relación.

+0

Configuración de la antigüedad. Interval lo hizo por mí. ¡Gracias! – MrMage

1

Esto funciona, excepto en aplicaciones de sandboxes. No puede enviar una notificación con un dict de información de usuario. En su lugar, considere algún otro IPC como XPC o DO.

En una nota lateral, usar NSDustributedNotificationCenter no siempre es 100% si el sistema está ocupado.

Cuestiones relacionadas