2012-03-06 11 views
6

Estoy creando una aplicación que recupera un conjunto de resultados de una base de datos. Utilizo MBProgressHUD para mostrar el progreso de la consulta con una animación. El método que uso llama a la animación mientras se ejecuta un método en otro hilo y, una vez hecho, oculta la animación. Mi pregunta es, después de llamar a:Multithreading en iOS: ¿cómo forzar a un hilo a esperar una condición?

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

me gustaría, si no hay resultados, muestra una alerta que indica esto, y si existen, cargue la siguiente vista. Hasta el momento, no 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 consigue el sistema al final del método getResults. Sin embargo, dado que se llama a ese método en otro hilo, esta línea de ejecución continúa y muestra la alerta, aunque haya eventos en la base de datos.

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

Gracias!

Respuesta

2

También podría considerar un NSConditionLock.

así que sería algo como esto en la rosca 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 de un bloque o un blanco/selector al HUD que debe realizar cuando se obtienen los resultados.

EDIT: por lo que iba a terminar con un 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 tipo HUD con la inteligencia adicional para tomar una dispatch_block_t como argumento final y para llamarlo cuando los resultados están en (garantizando el envío de vuelta al hilo principal o de lo contrario).

+0

Ya veo. ¡Aún tengo mucho que aprender sobre programación para iOS! Echaré un vistazo a eso. ¡Gracias! – KerrM

+0

El patrón 'pasar un bloque' es relativamente nuevo, pero parece ser la dirección hacia la que se dirigen las nuevas API en iOS 5. Ver, por ejemplo, 'TWRequest' o' ACAccountStore'. De hecho, probablemente sería mejor utilizar 'completionHandler:' en lugar de 'performWhenFinished:' para suministrar el bloque, según la convención que parece estar surgiendo. – Tommy

0

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

Quizás también establezca un tiempo de espera.

0

Esta es su manera: Concurrency Programming Guide

también: Synchronization

Más definición: Using Locks. Creo que el último podría brindar 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]; } 
11

Se puede utilizar un bucle de espera ocupada por 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” que es mejor usar una 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 tiempo de CPU .

La mejor solución es evitar el bloqueo y rediseñar el código para que funcione de forma asíncrona. En su caso, debe mostrar un girador y comenzar a descargar datos. Cuando los datos terminan de descargarse, debe recibir una devolución de llamada asincrónica (a través de un bloque o una devolución de llamada de destino/acción) y mostrar los resultados o mostrar la alerta de error. Bloquear con un bucle ocupado o un semáforo es la solución de un pobre en este caso.

+0

Gracias por la respuesta. Sinceramente, estoy completamente perdido cuando se trata de programar iOS, pero analizaré las devoluciones de llamada asincrónicas. ¡Gracias de nuevo! – KerrM

+0

Solo un comentario, dispatch_release no es necesario desde iOS6 –

0

puede utilizar como .. dispatch_time_t

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#> 
}); 
Cuestiones relacionadas