gcd

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

Retrasar la ejecución de un método en Cocoa

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

 

Fernando Rodríguez

Sígueme en twitter.
Cursos de desarrollo iPhone

Acerca de Fernando Rodriguez

Fundador & Editor Jefe de justcodeit, Fernando Rodríguez (@frr149 & Linkedin) es desarrollador & un experto en la enseñanza de máxima calidad en programación y desarrollo para dispositivos iOS, Cocoa Touch, Objective C, Swift, Python, entre otros, aunque su mejor carta de presentación, es la opinión de sus alumnos: http://keepcoding.io/es/testimonio/ CLO en KeepCoding & Arunovo. Instructor de iOS Avanzado del Big Nerd Ranch. Profesor Asociado de la U-tad, autor invitado de revistas como iPhoneWorld, Applesfera.com & ponente habitual en conferencias dentro y fuera de España (iOSDevUK, CodeMotion, BCNDevCon, etc). En sus vidas anteriores fue un nerd de Python y Django, mago de Smalltalk, y para su pesar, galeote de C++ y un gran cocinero.

Share this:

Leave a comment