¿Patrones de layout recomendados para bloques asíncronos?

Estoy trabajando en una aplicación de iOS que tiene un layout altamente asíncrono. Hay circunstancias en las que una única "operación" conceptual puede poner en queue muchos bloques secundarios que se ejecutarán de forma asíncrona y recibirán sus respuestas (llamadas al server remoto) de forma asíncrona. Cualquiera de estos bloques secundarios podría finalizar la ejecución en un estado de error. En caso de que se produzca un error en cualquier bloque secundario, se deben cancelar cualquier otro bloque secundario, el estado de error debe estar filtrado hasta el primario y el bloque de event handling errores del padre debe ejecutarse.

Me pregunto qué patrones de layout y otros consejos que podrían recomendarse para trabajar en un entorno como este.

Estoy al tanto de las capacidades de dispatch_group_async y dispatch_group_wait de GCD. Puede ser una falla en el layout de esta aplicación, pero no he tenido buena suerte con dispatch_group_async porque el grupo no parece estar "pegado" a los bloques secundarios.

¡Gracias por adelantado!

Hay un video de WWDC (2012) que probablemente lo ayude. Utiliza un NSOperationQueue personalizado y coloca los bloques asíncronos dentro de NSOperations para que pueda mantener un control sobre los bloques y cancelar los bloques en queue restantes.

Una idea sería tener el event handling errores de los bloques secundarios para llamar a un método en el hilo principal de la class que maneja el NSOperationQueue . La class podría cancelar el descanso apropiadamente. De esta manera, el locking infantil solo necesita saber sobre su propio hilo y el hilo principal. Aquí hay un enlace al video.

https://developer.apple.com/videos/wwdc/2012/

El video se llama "Creación de interfaces de usuario concurrentes en iOS". La parte relevante está principalmente en la segunda mitad, pero probablemente querrás verlo todo, ya que lo pone en context muy bien.

EDITAR:

Si es posible, recomiendo manejar la respuesta en un bloque embedded, que lo integra muy bien, que es lo que creo que buscas …

 //Define an NSBlockOperation, and get weak reference to it NSBlockOperation *blockOp = [[NSBlockOperation alloc]init]; __weak NSBlockOperation *weakBlockOp = blockOp; //Define the block and add to the NSOperationQueue, when the view controller is popped //we can call -[NSOperationQueue cancelAllOperations] which will cancel all pending threaded ops [blockOp addExecutionBlock: ^{ //Once a block is executing, will need to put manual checks to see if cancel flag has been set otherwise //the operation will not be cancelled. The check is rather pointless in this example, but if the //block contained multiple lines of long running code it would make sense to do this at safe points if (![weakBlockOp isCancelled]) { //substitute code in here, possibly use *synchronous* NSURLConnection to get //what you need. This code will block the thread until the server response //completes. Hence not executing the following block and keeping it on the //queue. __block NSData *temp; response = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]]; [operationQueue addOperationWithBlock:^{ if (error) { dispatch_async(dispatch_get_main_queue(), ^{ //Call selector on main thread to handle canceling //Main thread can then use handle on NSOperationQueue //to cancel the rest of the blocks }); else { //Continue executing relevant code.... } }]; } }]; [operationQueue addOperation:blockOp]; 

Un patrón que he encontrado desde la publicación de esta pregunta fue el uso de un semáforo para cambiar lo que sería una operación asíncrona en una operación síncrona. Esto ha sido bastante útil. Esta publicación de blog cubre el concepto con mayor detalle.

http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch-semaphore

Hay muchas forms de lograr un comportamiento asynchronous en el cocoa.

GCD, NSOperationQueue, performSelectorAfterDelay, creando sus propios hilos. Hay momentos apropiados para usar estos mecanismos. Demasiado time para discutir aquí, pero algo que mencionaste en tu publicación debe abordarse.

En caso de que se produzca un error en cualquier bloque secundario, cualquier otro bloque secundario debe ser cancelado, el estado de error debe ser filtrado hasta el padre y el bloque de event handling errores del padre debe ejecutarse.

Los bloques no pueden arrojar errores en la stack. Período.