¿Qué encontrarás en este post?
ToggleRetrasar la ejecución de un método en Objective C
En Cocoa tenemos la posibilidad de enviar un mensaje a un objeto pasados n segundos con performSelector:withObject:afterDelay: y demás métodos similares definidos en NSObject. Sin embargo, a veces se echa de menos el poder ejecutar código arbitrario (no necesariamente un método o solo un método) con un cierto retraso. Para retrasar ejecución de un método, hay dos soluciones, ambas basadas en Bloques.Primera solución: dispatch_after()
La función dispatch_after(), proporcionada por Grand Central Dispatch (GCD) acepta un cierto número de nanosegundos (tal como devuelve dispatch_time()), la cola en la que se va a ejecutar y un bloque de tipo void ^void. Es decir, no acepta parámetros ni devuelve nada. La falta de parámetros del bloque no es una limitación, ya que como recordaremos, los bloques capturan el entorno léxico donde se ejecutan. Un ejemplo de su uso podría ser:int64_t delta = 1.0e9 * 4; // 4 segundos expresados en nanosegundos dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, delta); dispatch_after(delay, dispatch_get_main_queue(), ^(void){ NSLog(@"Ya han pasado los 4 segundos!"); });Sin embargo, esta solución tiene varias pegas:
- No es orientada a objeto, ya que Grand Central Dispatch es una API de C.
- Nos obliga a escribir mucho código y carece de la sencillez y elegancia de performSelector:withObject:afterDelay:
Segunda solución: Una categoría sobre NSObject
Vamos a crear una categoría sobre NSObject, que le añade un método similar a performSelector:withObject:afterDelay: llamado performBlock:afterDelay:Interfase
#import @interface NSObject (NSObject_FRRObject) -(void)performBlock:(void (^)(void))block afterDelay: (NSTimeInterval) delayInSeconds; @end
Implementación
#import "NSObject+FRRObject.h" @implementation NSObject (NSObject_FRRObject) -(void)performBlock:(void (^)(void))block afterDelay: (NSTimeInterval) delayInSeconds{ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), block); }@end
Uso
[self performBlock:^{ NSLog(@"En dos palabras y 3 segundos, ObjectiveC es IM PRESIONANTE");} afterDelay:3];