Necesito obtener el tiempo transcurrido entre dos eventos, por ejemplo, la aparición de una UIView y la primera reacción del usuario.
¿Cómo puedo lograrlo en Objective-C?
Necesito obtener el tiempo transcurrido entre dos eventos, por ejemplo, la aparición de una UIView y la primera reacción del usuario.
¿Cómo puedo lograrlo en Objective-C?
Respuestas:
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
es la diferencia entre inicio y ahora, en segundos, con precisión de menos de milisegundos.
[NSDate date]
puede conducir a errores difíciles de rastrear, vea esta respuesta para obtener más información.
No debe confiar en él [NSDate date]
para fines de tiempo ya que puede informar en exceso o por debajo del tiempo transcurrido. ¡Incluso hay casos en los que su computadora aparentemente viajará en el tiempo ya que el tiempo transcurrido será negativo! (Por ejemplo, si el reloj se movió hacia atrás durante el tiempo).
De acuerdo con Aria Haghighi en la conferencia "Reconocimiento avanzado de gestos iOS" del curso de invierno 2013 Stanford iOS (34:00), debe usarla CACurrentMediaTime()
si necesita un intervalo de tiempo preciso.
C objetivo:
#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
Rápido:
let startTime = CACurrentMediaTime()
// perform some action
let elapsedTime = CACurrentMediaTime() - startTime
La razón es que se [NSDate date]
sincroniza en el servidor, por lo que podría provocar "problemas de sincronización de tiempo" que pueden conducir a errores muy difíciles de rastrear. CACurrentMediaTime()
, por otro lado, es un tiempo de dispositivo que no cambia con estas sincronizaciones de red.
Deberá agregar el marco QuartzCore a la configuración de su objetivo.
[NSDate date]
dentro de un bloque de finalización dentro de un bloque de despacho, recibía el mismo tiempo "actual" que informaba [NSDate date]
inmediatamente antes de que la ejecución llegara al punto en el que se crearon mis bloques. CACurrentMediaTime()
resuelto este problema
CACurrentMediaTime()
deja de hacer tictac cuando el dispositivo entra en suspensión. Si prueba con el dispositivo desconectado de una computadora, bloquéelo, luego espere ~ 10 minutos y verá que CACurrentMediaTime()
no cumple con la hora del reloj de pared.
Usa el timeIntervalSinceDate
método
NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];
NSTimeInterval
es solo un double
, definir NSDate
así:
typedef double NSTimeInterval;
Para cualquiera que venga aquí en busca de una implementación getTickCount () para iOS, aquí está el mío después de juntar varias fuentes.
Anteriormente tenía un error en este código (primero lo dividí por 1000000) que estaba causando cierta cuantificación de la salida en mi iPhone 6 (tal vez esto no fue un problema en el iPhone 4 / etc o simplemente nunca lo noté). Tenga en cuenta que al no realizar esa división primero, existe cierto riesgo de desbordamiento si el numerador de la base de tiempo es bastante grande. Si alguien tiene curiosidad, hay un enlace con mucha más información aquí: https://stackoverflow.com/a/23378064/588476
A la luz de esa información, ¡quizás sea más seguro usar la función de Apple CACurrentMediaTime
!
También mach_timebase_info
comparé la llamada y toma aproximadamente 19ns en mi iPhone 6, así que eliminé el código (no seguro) que estaba almacenando en caché la salida de esa llamada.
#include <mach/mach.h>
#include <mach/mach_time.h>
uint64_t getTickCount(void)
{
mach_timebase_info_data_t sTimebaseInfo;
uint64_t machTime = mach_absolute_time();
// Convert to milliseconds
mach_timebase_info(&sTimebaseInfo);
machTime *= sTimebaseInfo.numer;
machTime /= sTimebaseInfo.denom;
machTime /= 1000000; // convert from nanoseconds to milliseconds
return machTime;
}
Tenga en cuenta el riesgo potencial de desbordamiento dependiendo de la salida de la llamada a la base de tiempo. Sospecho (pero no sé) que podría ser una constante para cada modelo de iPhone. en mi iPhone 6 lo fue 125/3
.
La solución usando CACurrentMediaTime()
es bastante trivial:
uint64_t getTickCount(void)
{
double ret = CACurrentMediaTime();
return ret * 1000;
}
mach_timebase_info()
se restablecerá pasado en mach_timebase_info_data_t
que {0,0}
antes de que a los valores reales, que pueden causar la división por cero si el código es llamado desde varios subprocesos. Use en su dispatch_once()
lugar (o CACurrentMediaTime
que es solo tiempo de máquina convertido a segundos).
Para medidas de tiempo precisas (como GetTickCount), también eche un vistazo a mach_absolute_time y este Q&A de Apple: http://developer.apple.com/qa/qa2004/qa1398.html .
use la función timeIntervalSince1970 de la clase NSDate como se muestra a continuación:
double start = [startDate timeIntervalSince1970];
double end = [endDate timeIntervalSince1970];
double difference = end - start;
Básicamente, esto es lo que uso para comparar la diferencia en segundos entre 2 fechas diferentes. también revise este enlace aquí
Las otras respuestas son correctas (con una advertencia *). Agrego esta respuesta simplemente para mostrar un ejemplo de uso:
- (void)getYourAffairsInOrder
{
NSDate* methodStart = [NSDate date]; // Capture start time.
// … Do some work …
NSLog(@"DEBUG Method %s ran. Elapsed: %f seconds.", __func__, -([methodStart timeIntervalSinceNow])); // Calculate and report elapsed time.
}
En la consola del depurador, verá algo como esto:
DEBUG Method '-[XMAppDelegate getYourAffairsInOrder]' ran. Elapsed: 0.033827 seconds.
* Advertencia: como otros han mencionado, úselo NSDate
para calcular el tiempo transcurrido solo para fines casuales. Uno de esos propósitos podría ser la prueba común, la elaboración de perfiles en bruto, donde solo desea una idea aproximada de cuánto tiempo lleva un método.
El riesgo es que la configuración de la hora actual del reloj del dispositivo podría cambiar en cualquier momento debido a la sincronización del reloj de la red. Entonces el NSDate
tiempo podría saltar hacia adelante o hacia atrás en cualquier momento.
fabs(...)
para obtener el valor absoluto de un flotador. P.ej.NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);