Cómo retrasar la ejecución de un método en Objective C

| Última modificación: 17 de abril de 2024 | Tiempo de Lectura: 2 minutos

Algunos de nuestros reconocimientos:

Premios KeepCoding

Retrasar 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];

Conclusión

Al utilizar una categoría sobre NSObject podemos unir la flexibilidad de los bloques, con la sencillez y elegancia de performSelector:withObject:afterDelay: encapsulando así la API C de Grand Central Dispatch (GCD). Así, puedes retrasar la ejecución de un método en Objective C.

Fernando Rodríguez

Sígueme en twitter. Bootcamps de programación
Fernando Rodríguez

iOS Developer & Co-Fundador de KeepCoding

Posts más leídos