iphone - español - Bloques en lugar de performSelector: withObject: afterDelay:
cocoa touch español (6)
Esta pregunta ya tiene una respuesta aquí:
A menudo quiero ejecutar algún código unos microsegundos en el futuro. En este momento, lo resuelvo así:
- (void)someMethod
{
// some code
}
Y esto:
[self performSelector:@selector(someMethod) withObject:nil afterDelay:0.1];
Funciona, pero tengo que crear un nuevo método todo el tiempo. ¿Es posible usar bloques en lugar de esto? Básicamente estoy buscando un método como:
[self performBlock:^{
// some code
} afterDelay:0.1];
Eso sería realmente útil para mí.
Aquí hay una técnica simple, basada en GCD, que estoy usando:
void RunBlockAfterDelay(NSTimeInterval delay, void (^block)(void))
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*delay),
dispatch_get_current_queue(), block);
}
No soy un experto en GCD, y me interesarían los comentarios sobre esta solución.
Hay una categoría agradable y completa que maneja esta situación aquí:
No hay una forma incorporada de hacerlo, pero no está mal agregarlo a través de una categoría:
@implementation NSObject (PerformBlockAfterDelay)
- (void)performBlock:(void (^)(void))block
afterDelay:(NSTimeInterval)delay
{
block = [[block copy] autorelease];
[self performSelector:@selector(fireBlockAfterDelay:)
withObject:block
afterDelay:delay];
}
- (void)fireBlockAfterDelay:(void (^)(void))block {
block();
}
@end
Gracias a Mike Ash por la implementación básica.
Otra forma (quizás la peor forma de hacer esto por muchas razones) es:
[UIView animateWithDuration:0.0 delay:5.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
} completion:^(BOOL finished) {
//do stuff here
}];
Si específicamente necesita un retraso mayor, las soluciones anteriores funcionan bien. He utilizado el enfoque de @ nick con gran éxito.
Sin embargo, si solo quiere que su bloque se ejecute durante la siguiente iteración del ciclo principal, puede recortarlo aún más con solo lo siguiente:
[[NSOperationQueue mainQueue] addOperationWithBlock:aBlock];
Esto es similar a usar performSelector: con afterDelay de 0.0f
Usé un código similar como este:
double delayInSeconds = 0.2f;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//whatever you wanted to do here...
});