Saltar al contenido →

NSTimer vs dispatch_source_t

Que usar un NSTimer para ejecutar acciones tras un determinado periodo de tiempo es algo que hasta la propia Apple desaconseja si lo que estás buscando es precisión a la hora de que se ejecute tu código.

A timer is not a real-time mechanism

Pero todo hemos hecho alguna prueba y oye, parece que la cosa no es tan mala como la pintan, de hecho no aparece ni rastro de esos lapsos de tiempo perdidos a los que se refiere la documentación.

Eso es porque hemos probado ejecutando desde Xcode con un periodo de tiempo corto (somos muy impacientes) y tampoco es que hayamos dejado la prueba corriendo un par de horas. Y sobre todo, porque no lo habéis hecho para un proyecto OS X (macOS desde el 13 de junio).

Hace poco publiqué una app para los usuarios de la técnica Pomodoro, y el consejo que puedo daros es que os creáis la documentación a pies juntillas, sobre todo si lo que vais a ejecutar con procesos de larga duración, y no es que NSTimer falle en estos casos por segundos, que va, falla por minutos, muchos minutos.

App Nap. Ahorrando energia en tu Mac.

Uno de los culpables del comportamiento de los NSTimer es App Nap, esta característica que incoporora OS X a nivel de sistema permite ahorrar energia poniendo a dormir las aplicaciones que menos actividad tengan, y uno de los efectos que tiene es…

Timer throttling, which reduces the frequency with which the app’s timers are fired

¿Y cómo sé si mi aplicación es candidata a App Nap? Normalmente lo es si cumple con alguno de los siguientes requisitos

  • No está en primer plano
  • No ha actualizado recientemente el contenido en la parte visible de su — ventana
  • No se la oye (no reproduce sonido)
  • No hemos especificado ninguna regla para NSProcessInfo o la gestión de energía de IOKit
  • No hace uso de OpenGL

¿Qué hago entonces?

No hay de que preocuparse, existe una forma de ejecutar temporizadores de manera muy precisa aunque tu aplicación entre en modo App Nap, y esa manera tiene por nombre dispatch_source_set_timer, que pertenece a GCD.

Pero por si mismo no es un temporizador fiable, tal y como podemos leer en la documentación, para que nos podamos fiar de él necesitamos de la ayuda de otro elemento de GCD conocido como dispatch_walltime.

¿Y por qué? Porque si creamos el dispatch_source_set_timer usando el reloj del sistema nuestro proceso no se ejecutará si macOS entra en suspensión, ya que el mismo reloj del sistema se queda dormido, mientras que dispatch_walltime hace uso de lo que se llama wall clock, que es inmune al estado de suspensión.

Vamos a ver un ejemplo donde vamos a crear un temporizador que se lanza cada 60 segundos con una demora permitida de 1 segundo.

Espera, ¿has dicho demora?. Sí, el método permite especificar margen de tiempo para el lanzamiento del temporizados, y no, aunque pongas ese valor a cero no se asegura que tu temporizador se lance con total precisión.

Conclusión

Al final el usar NSTimer o dispatch_source_t dependerá de la naturaleza del temporizador que quieras programar, de la importancia de la tarea y de si es necesario que se ejcute cuando el usuario no está mirando.

Publicado en Swift

Comentarios

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *