La mejor práctica para escribir resources desde dos processs diferentes en el objective c

Tengo un patrón general objective / pregunta de práctica relativa a un problema que trato de resolver con mi aplicación. No pude encontrar una pregunta / respuesta cinput en el objective-c similar aquí, todavía.

Mi aplicación tiene una matriz mutable de objects que llamo "loggings". La aplicación recostack loggings y los coloca en esa matriz de una de dos maneras:

  1. Lee datos de una database SQLite disponible localmente dentro del cuadro de arena de la aplicación. La lectura suele ser muy rápida.
  2. Solicita datos de forma asíncrona desde un service web, espera a que termine y luego analiza los datos. La lectura puede ser rápida, pero a menudo no lo es.

A veces la aplicación lee desde la database (1) y solicita datos del service web (2) esencialmente al mismo time. A menudo ocurre que (1) terminará antes (2) termina y agregar loggings a la matriz mutable no provoca un conflicto.

Me preocupa que, en algún momento, mi process de lectura SQLite tome un poco más de lo esperado e intentará agregar objects a la matriz mutable exactamente al mismo time que la request asincrónica termina y hace lo mismo; o viceversa. Estos son casos extremos que parecen difíciles de probar, pero eso seguramente haría que mi aplicación se bloquee o, al less, cause problemas con mi matriz de loggings.

También debería señalar que los loggings se combinarán en la matriz mutable. Por ejemplo: si (1) se ejecuta primero y devuelve 10 loggings, poco después (2) termina y devuelve 5 loggings, mi matriz mutable contendrá los 15 loggings. Estoy combinando los datos en lugar de sobrescribirlos.

Lo que quiero saber es:

  • ¿Es seguro para mí agregar objects a la misma instancia de matriz mutable cuando finalizan los processs, (1) o (2)?
  • ¿Hay un buen patrón / práctica para implementar para este tipo de procesamiento en el objective c?
  • ¿Esto implica bloquear el acceso a la matriz mutable, de modo que cuando (1) está agregando objects a ella (2) no puede agregar ningún object hasta que (1) termine con ella?

Aprecio cualquier información que pueda compartir.

[EDITAR 1]

Para la posteridad, encontré esta URL para ser de gran ayuda en la comprensión de cómo usar NSOperations y un NSOperationQueue. Está un poco desactualizado, pero funciona, no obstante:

How To Use NSOperations and NSOperationQueues

Además, no habla específicamente sobre el problema que estoy tratando de resolver, pero el ejemplo que usa es práctico y fácil de entender.

[EDITAR 2]

He decidido seguir el enfoque sugerido por danh, donde leeré localmente y, según sea necesario, accederé a mi service web después de que la lectura local haya finalizado (lo que debería ser rápido de todos modos). Dijo Taht, voy a tratar de evitar los problemas de synchronization por completo. ¿Por qué? Porque Apple lo dice, aquí:

http://developer.apple.com/library/IOS/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW8

Evitar la synchronization en set

Para cualquier proyecto nuevo en el que trabaje, e incluso para proyectos existentes, el layout de su código y estructuras de datos para evitar la necesidad de synchronization es la mejor solución posible. Aunque los lockings y otras herramientas de synchronization son útiles, afectan el performance de cualquier aplicación. Y si el layout general provoca una gran contención entre resources específicos, tus hilos podrían estar esperando incluso más time.

La mejor manera de implementar la concurrency es networkingucir las interacciones e interdependencies entre sus tareas simultáneas. Si cada tarea opera en su propio set de datos privado, no necesita proteger esos datos usando lockings. Incluso en situaciones donde dos tareas comparten un set de datos común, puede ver forms de particionar ese set o proporcionar a cada tarea su propia copy. Por supuesto, copyr sets de datos también tiene sus costos, por lo que debe sopesar esos costos con los costos de synchronization antes de tomar una decisión.

¿Es seguro para mí agregar objects a la misma instancia de matriz mutable cuando finalizan los processs, (1) o (2)?

Absolutamente no. NSArray, junto con el rest de las classs de colección, no están sincronizados . Puede usarlos junto con algún tipo de locking cuando agrega y elimina objects, pero definitivamente es mucho más lento que hacer dos arreglos (uno para cada operación) y fusionarlos cuando ambos terminen.

¿Hay un buen patrón / práctica para implementar para este tipo de procesamiento en el objective c?

Lamentablemente no. Lo máximo que puede llegar a hacer es disparar un boolean o incrementar un número integer a un cierto número en una callback común. Para ver lo que quiero decir, aquí hay un pequeño pseudo-código:

- (void)someAsyncOpDidFinish:(NSSomeOperation*)op { finshedOperations++; if (finshedOperations == 2) { finshedOperations = 0; //Both are finished, process } } 

¿Esto implica bloquear el acceso a la matriz mutable, de modo que cuando (1) está agregando objects a ella (2) no puede agregar ningún object hasta que (1) termine con ella?

Sí, ver arriba.

Debe bloquear las modificaciones de su matriz o progtwigr sus modificaciones en el hilo principal. Es probable que la búsqueda de SQL se esté ejecutando en el hilo principal, por lo que en su código de búsqueda remoto podría hacer algo como:

 dispatch_async(dispatch_get_main_queue(), ^{ [myArray addObject: newThing]; }]; 

Si está agregando un montón de objects, esto será lento ya que está poniendo una nueva tarea en el progtwigdor para cada logging. Puede agrupar los loggings en una matriz separada en el subprocess y agregar la matriz temporal utilizando addObjectsFromArray: si ese es el caso.

Personalmente, me gustaría tener un NSOperationQueue concurrente y agregar las dos operaciones de operaciones de recuperación, una para la operación de la database, otra para la operación de la networking. Entonces tendría una queue de serie dedicada para agregar los loggings a NSMutableArray , que cada una de las dos operaciones de recuperación simultáneas utilizaría para agregar loggings a la matriz mutable. De esa forma, tiene una queue para agregar loggings, pero se alimenta de las dos operaciones de recuperación que se ejecutan en la otra, queue simultánea. Si necesita saber cuándo se realizan las dos operaciones de recuperación simultáneas, agregaría una tercera operación a esa queue simultánea, establezca sus dependencies para que sean las dos operaciones de recuperación, que se dispararán automáticamente cuando se realicen las dos operaciones de recuperación.

Además de las buenas sugerencias anteriores, considere no iniciar el GET y el sql simultáneamente.

 [self doTheLocalLookupThen:^{ // update the array and ui [self doTheServerGetThen:^{ // update the array and ui }]; }]; - (void)doTheLocalLookupThen:(void (^)(void))completion { if ([self skipTheLocalLookup]) return completion(); // do the local lookup, invoke completion } - (void)doTheServerGetThen:(void (^)(void))completion { if ([self skipTheServerGet]) return completion(); // do the server get, invoke completion }