Multiprocess en iOS: ¿cómo forzar un hilo a esperar una condición?

Estoy creando una aplicación que obtiene un set de resultados de una database: uso MBProgressHUD para mostrar el progreso de la consulta con una animation. El método que uso llama a la animation mientras se ejecuta un método en otro subprocess y, una vez hecho, oculta la animation. Mi pregunta es, después de llamar:

[HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES]; 

Me gustaría, si no hay resultados, mostrar una alerta que indique esto, y si los hay, cargue la siguiente vista. Hasta ahora, tengo este código:

 [HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES]; if(self.thereAreEvents) { [self performSegueWithIdentifier:@"searchResults" sender:self]; } else { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No results" message:@"Sorry, there are no results for your search. Please try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; [alert release]; } 

self.thereAreEvents se establece al final del método getResults . Sin embargo, dado que ese método recibe un llamado en otro hilo, esta línea de ejecución continúa y muestra la alerta, aunque haya events en la database.

Entonces, a partir de aquí, tengo dos preguntas: ¿Cuál es la forma más fácil de implementar un mecanismo de señal de espera en iOS y cuál es la manera más eficiente de implementar este tipo de mecanismo en iOS?

¡Gracias!

También podría considerar un NSConditionLock .

Entonces sería algo así en el subprocess 1:

 [conditionLock lockWhenCondition:kConditionOkayToProceed]; [conditionLock unlockWithCondition:kConditionGettingResults]; [HUD show...] [conditionLock lockWhenCondition:kConditionResultsFetched]; [conditionLock unlockWithCondition:kConditionOkayToProceed]; 

Y en el HUD:

 - (void)show... { [conditionLock lockWhenCondition:kConditionGettingResults]; // stuff here [conditionLock unlockWithCondition:kConditionResultsFetched]; } 

Aunque una solución mucho mejor sería pasar un bloque o un objective / selector al HUD que es realizar cuando se obtienen los resultados.

EDITAR: por lo que terminaría con código como:

 [HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES performWhenFinished: ^{ if(self.thereAreEvents) { [self performSegueWithIdentifier:@"searchResults" sender:self]; } else { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No results" message:@"Sorry, there are no results for your search. Please try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; [alert release]; } }]; 

Y en el HUD:

 - (void)showWhile... performWhenFinished:(dispatch_block_t)block { // all the other stuff you were going to do here, then // eventually... // if no guarantees, maybe just: block(); // otherwise, if promised to dispatch to the main queue: dispatch_async(dispatch_get_main_queue(), block); } 

Con HUD tener la inteligencia extra para tomar un dispatch_block_t como un argumento final y llamarlo cuando los resultados estén (ya sea garantizando el envío de return al hilo principal o de lo contrario).

Puede usar un ciclo de espera ocupado para una solución rápida y sucia:

 __block BOOL finished = NO; dispatch_async(/* global queue */, ^{ // … finished = YES; }); while (!finished) /* waiting */; 

En el código "real" es mejor usar un semáforo:

 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_async(/* global queue */, ^{ // … dispatch_semaphore_signal(semaphore); }); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_release(sempahore); 

Esto es mejor que el bucle ocupado porque el hilo bloqueado no consume time de CPU.

La mejor solución es evitar el locking y el networkingiseño de su código para que funcione de forma asíncrona. En su caso, debe mostrar una ruleta y comenzar a download datos. Cuando los datos terminen de downloadse, debe recibir una callback asíncrona (ya sea a través de un bloque o una callback de destino / acción) y mostrar los resultados o mostrar la alerta de error. Bloquear con un ciclo ocupado o un semáforo es la solución de un hombre pobre en este caso.

No estoy seguro de si esta es la mejor manera de hacerlo, pero intentaría usar un ciclo while para observar algo boolean con algo como [NSThread sleepForTimeInterval: 1]; dentro del bucle

Tal vez establezca un time de espera también.

Este es tu path: Guía de progtwigción de simultaneidad

También: synchronization

Más agudo: usando cerraduras . Creo que el último podría dar la mejor ayuda.

Otro enfoque simple, es malo pero funciona

 NSAssert(![NSThread isMainThread], @"Do not run on MAIN thread"); while (yourCondition) { [NSThread sleepForTimeInterval:0.2]; } 

puedes usar dispatch_time_t como …

 double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ <#code to be executed on the main queue after delay#> });