Bloques en lugar de performSelector: withObject: afterDelay:

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í.

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.

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.

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... }); 

Hay una categoría agradable y completa que maneja esta situación aquí:

https://gist.github.com/955123