2012-07-31 9 views
6

Sto lavorando a un'applicazione iOS con un design altamente asincrono. Vi sono circostanze in cui una singola "operazione" concettuale può accodare molti blocchi figlio che verranno entrambi eseguiti in modo asincrono e ricevere le loro risposte (chiamate al server remoto) in modo asincrono. Ognuno di questi blocchi figlio potrebbe terminare l'esecuzione in uno stato di errore. Se si verifica un errore in qualsiasi blocco figlio, tutti gli altri blocchi figlio devono essere annullati, lo stato di errore deve essere percolato fino al genitore e il blocco di gestione degli errori del genitore deve essere eseguito.Modelli di progettazione consigliati per i blocchi asincroni?

Mi chiedo quali motivi di progettazione e altri suggerimenti che potrebbero essere consigliati per lavorare in un ambiente come questo?

Sono a conoscenza delle funzionalità dispatch_group_async e dispatch_group_wait di GCD. Potrebbe essere un difetto nel design di questa app, ma non ho avuto fortuna con dispatch_group_async perché il gruppo non sembra essere "appiccicoso" ai blocchi figlio.

Grazie in anticipo!

risposta

5

C'è un video WWDC (2012) che probabilmente ti aiuterà. Utilizza un numero personalizzato NSOperationQueue e inserisce i blocchi asincroni all'interno di NSOperations in modo da poter mantenere un handle sui blocchi e annullare i blocchi rimanenti in coda.

Un'idea sarebbe quella di avere la gestione degli errori dei blocchi figlio per chiamare un metodo sul thread principale nella classe che gestisce lo NSOperationQueue. La classe potrebbe quindi cancellare il resto in modo appropriato. In questo modo il blocco figlio deve solo conoscere la propria discussione e il thread principale. Ecco un link al video

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

Il video si chiama "Costruire Interfacce utente simultanee su iOS". La parte rilevante è principalmente nella seconda parte, ma probabilmente vorrai vedere l'intera cosa nel suo contesto.

EDIT:

Se possibile, mi consiglia di maneggiare la risposta in un blocco incorporato che avvolge piacevolmente insieme, che è quello che penso che stai dopo ..

//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

Grazie, ho guardato il video. Immagino che cosa stia inciampando su come un'operazione possa essere essenzialmente mantenuta in coda mentre è in attesa di una risposta asincrona ...? Sarebbe comodo essere in grado di sfruttare NSOperationQueue. Ho usato quella classe in altre app, ma in precedenza avevo solo la coda per gestire le richieste in uscita, non l'elaborazione della risposta. In questa app, l'operazione non viene eseguita finché non viene elaborata la risposta e vengono completate anche eventuali richieste secondarie associate. – xyzzycoder

+0

puoi inserire il codice di gestione della risposta in un blocco incorporato? Aggiornerò la mia risposta –

+0

Se ci si trova nel mondo 'NSOperation', piuttosto che in' dispatch_async (dispatch_get_main_queue(),^{}); ', perché no' [[NSOperationQueue mainQueue] addOperationWithBlock:^{}]; ' ? Quello che hai va bene, ma è strano mescolare le chiamate GCD con le chiamate 'NSOperationQueue'. – Rob

-1

Ci sono molti modi per ottenere un comportamento asincrono nel cacao.

GCD, NSOperationQueue, performSelectorAfterDelay, creazione di thread personalizzati. Ci sono momenti appropriati per utilizzare questi meccanismi. Troppo a lungo per discutere qui, ma qualcosa che hai menzionato nel tuo post deve essere affrontata.

Nel caso in cui si verifichi un errore in un blocco figlio, tutti gli altri blocchi figlio devono essere annullati, lo stato di errore deve essere percolato fino al genitore e il blocco di gestione degli errori del genitore deve essere eseguito.

I blocchi non possono generare errori nello stack. Periodo.

+0

Grazie. In questa app, ho un canale di comunicazione con il server e le operazioni client/server sono implicitamente seriali. Non sto cercando di passare alcun errore in cima allo stack. – xyzzycoder

+0

Quindi, tutto ciò che serve è una chiamata asincrona - usa GCD o crea il tuo thread. –

Problemi correlati