2011-02-09 16 views
8

uno de los principios centrales de la arquitectura de mi última aplicación es que voy a llamar a métodos en el modelo de la aplicación que serán asíncronos y aceptarán escenario de fracaso y éxito bloques.Método de invocación de modelo con bloque que se ejecutará en el hilo principal

es decir, la interfaz de usuario llama al método del modelo con 2 bloques, uno para el éxito y el otro para el fracaso.

Esto es genial porque se conserva el contexto de la llamada original, sin embargo, el bloque en sí se llama en el hilo de fondo. ¿Hay alguna forma de llamar a un bloque en el hilo principal?

Esperemos que lo haya expirado bien, si no, básicamente, mis métodos de modelo son asincrónicos, regrese inmediatamente y cree un nuevo hilo para ejecutar el op. Una vez que la opción de respuesta invoque un bloque que posprocesará los datos devueltos, ENTONCES necesito llamar al bloque para el escenario de éxito definido por el llamado dentro de la UI. Sin embargo, los bloques de escenarios de éxito y fracaso definidos en la interfaz de usuario deben invocarse en el hilo principal porque necesito interactuar con los elementos de la interfaz de usuario, lo que solo debería hacerse en el hilo principal, creo.

muchas gracias

Respuesta

36

Algo como esto es probablemente lo que está buscando:

- (void) doSomethingWhichTakesAgesWithArg: (id) theArg 
          resultHandler: (void (^)(BOOL, id, NSError *)) handler 
{ 
    // run in the background, on the default priority queue 
    dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
     id someVar = [theArg computeSomething]; 

     NSError * anError = nil; 
     [someVar transmuteSomehowUsing: self error: &anError]; 

     // call the result handler block on the main queue (i.e. main thread) 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      // running synchronously on the main thread now -- call the handler 
      handler((error == nil), theArg, anError); 
     }); 
    }); 
} 
5

NSObject tiene un método:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait 

Crear un método que toma un parámetro NSDictionary en una clase práctica que siempre va a estar alrededor (como delegado de la aplicación, o un objeto Singleton) , el paquete de bloque y sus parámetros en un NSDictionary o NSArray, y llamar a

[target performSelectorOnMainThread:@selector(doItSelector) withObject:blockAndParameters waitUntilDone:waitOrNot]; 
10

Si está utilizando GCD, puede utilizar la opción "obtener cola principal":

dispatch_queue_t dispatch_get_main_queue() 

Llámalo dentro de un envío asíncrono. es decir

dispatch_async(dispatch_get_main_queue(), ^{ 
    /* Do somthing here with UIKit here */ 
}) 

El bloque ejemplo anterior podría estar ejecutándose en una cola de fondo asíncrono y el código de ejemplo sería enviar el trabajo de interfaz de usuario fuera a la rosca principal.

6

enfoque similar funciona también con NSOperationQueue:

NSBlockOperation *aOperation = [NSBlockOperation blockOperationWithBlock:^ 
{ 
    if (status == FAILURE) 
    { 
     // Show alert -> make sure it runs on the main thread 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^ 
     { 
      UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Alert" message:@"Your action failed!" delegate:nil 
             cancelButtonTitle:@"Ok" otherButtonTitles:nil] autorelease]; 
      [alert show]; 
     }]; 
    } 
}]; 

// myAsyncOperationQueue is created somewhere else 
[myAsyncOperationQueue addOperation:aOperation]; 
Cuestiones relacionadas