2012-07-31 9 views
6

Estoy trabajando en una aplicación iOS que tiene un diseño altamente asincrónico. Hay circunstancias en las que una única "operación" conceptual puede poner en cola muchos bloques secundarios que se ejecutarán de forma asincrónica y recibirán sus respuestas (llamadas al servidor remoto) de forma asincrónica. Cualquiera de estos bloques secundarios podría terminar la ejecución en un estado de error. En caso de que ocurra un error en cualquier bloque secundario, cualquier otro bloque secundario debe cancelarse, el estado de error debe filtrarse hasta el padre y debe ejecutarse el bloque de administración de errores del padre.Patrones de diseño recomendados para bloques asíncronos?

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

Conozco las capacidades dispatch_group_async y dispatch_group_wait de GCD. Puede ser un error en el diseño de esta aplicación, pero no he tenido suerte con dispatch_group_async porque el grupo no parece ser "adherente" a los bloques secundarios.

¡Gracias de antemano!

Respuesta

5

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 restantes en cola.

Una idea sería tener el manejo de errores de los bloques secundarios para llamar a un método en el hilo principal en la clase que maneja el NSOperationQueue. La clase podría cancelar el resto apropiadamente. De esta forma, el bloqueo para niños solo necesita conocer su propio hilo y el hilo principal. Aquí hay un enlace al video

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

El video se llama "La construcción de interfaces de usuario concurrentes en iOS". La parte relevante se encuentra principalmente en la segunda mitad, pero es probable que desee ver todo, ya que lo contextualiza.

EDIT:

Si es posible, me gustaría recomendar el manejo de la respuesta en un bloque incorporado, que lo envuelve muy bien juntos, que es lo que pienso que está buscando ..

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

Gracias, he visto el video. Supongo que lo que estoy tropezando es cómo una operación esencialmente puede mantenerse en la cola mientras espera una respuesta asincrónica ...? Sería conveniente poder aprovechar NSOperationQueue. He usado esa clase anteriormente en otras aplicaciones, pero anteriormente solo hacía que la cola manejara las solicitudes de salida, no el procesamiento de respuesta. En esta aplicación, la operación no finaliza hasta que se procesa la respuesta y las solicitudes secundarias asociadas también se completan. – xyzzycoder

+0

¿puedes poner el código de manejo de respuesta en un bloque integrado? Actualizaré mi respuesta –

+0

Si está en el mundo 'NSOperation', en lugar de' dispatch_async (dispatch_get_main_queue(),^{}); ', ¿por qué no' [[NSOperationQueue mainQueue] addOperationWithBlock:^{}]; ' ? Lo que tienes está bien, pero se siente extraño mezclar llamadas GCD con llamadas 'NSOperationQueue'. – Rob

-1

Hay muchas formas de lograr un comportamiento asincrónico en el cacao.

GCD, NSOperationQueue, performSelectorAfterDelay, creando sus propios hilos. Hay momentos apropiados para usar estos mecanismos. Demasiado tiempo para debatir aquí, pero algo que usted mencionó en su publicación debe abordarse.

En caso de que se produzca un error en cualquier bloque secundario, cualquier otro bloque secundario debe cancelarse, el estado de error debe filtrarse hasta el padre y debe ejecutarse el bloque de gestión de errores del padre.

Los bloques no pueden arrojar errores a la pila. Período.

+0

Gracias. En esta aplicación, tengo un canal de comunicación con el servidor, y las operaciones cliente/servidor son implícitas en serie. No estoy tratando de pasar ningún error en la pila. – xyzzycoder

+0

Entonces, todo lo que necesita es una llamada asíncrona: use GCD o cree su propio hilo. –