Preciso calcular o tempo decorrido entre dois eventos, por exemplo, a aparência de um UIView e a primeira reação do usuário.
Como posso alcançá-lo no Objective-C?
Preciso calcular o tempo decorrido entre dois eventos, por exemplo, a aparência de um UIView e a primeira reação do usuário.
Como posso alcançá-lo no Objective-C?
Respostas:
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
é a diferença entre iniciar e agora, em segundos, com precisão abaixo de milissegundos.
[NSDate date]
pode levar a erros de rastreamento difíceis, consulte esta resposta para obter mais informações.
Você não deve confiar [NSDate date]
para fins de tempo, pois isso pode subestimar ou subnotificar o tempo decorrido. Existem até casos em que seu computador aparentemente viaja no tempo, já que o tempo decorrido será negativo! (Por exemplo, se o relógio retroceder durante o tempo.)
De acordo com Aria Haghighi na palestra "Reconhecimento avançado de gestos para iOS" do curso de inverno de 2013 em Stanford para iOS (34:00), você deve usar CACurrentMediaTime()
se precisar de um intervalo de tempo preciso.
Objetivo-C:
#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
O motivo é que a [NSDate date]
sincronização no servidor pode levar a "soluços de sincronização de tempo", o que pode levar a erros muito difíceis de rastrear. CACurrentMediaTime()
, por outro lado, é um horário do dispositivo que não muda com essas sincronizações de rede.
Você precisará adicionar a estrutura QuartzCore às configurações do seu alvo.
[NSDate date]
dentro de um bloco de conclusão dentro de um bloco de despacho, eu estava recebendo o mesmo horário "atual" relatado [NSDate date]
imediatamente antes da execução atingir o ponto em que meus blocos foram criados. CACurrentMediaTime()
resolveu esse problema.
CACurrentMediaTime()
para de marcar quando o dispositivo entra no modo de suspensão. Se você testar com o dispositivo desconectado de um computador, bloqueie-o e aguarde ~ 10 minutos para descobrir que CACurrentMediaTime()
não acompanha o relógio de parede.
Use o timeIntervalSinceDate
método
NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];
NSTimeInterval
é apenas a double
, defina NSDate
assim:
typedef double NSTimeInterval;
Para quem vem aqui procurando uma implementação getTickCount () para iOS, aqui está o meu depois de reunir várias fontes.
Anteriormente, eu tinha um bug neste código (dividido por 1000000 primeiro), que estava causando uma quantização da saída no meu iPhone 6 (talvez esse não fosse um problema no iPhone 4 / etc ou simplesmente nunca percebi). Observe que, ao não executar essa divisão primeiro, há algum risco de estouro se o numerador da base de tempo for bastante grande. Se alguém estiver curioso, há um link com muito mais informações aqui: https://stackoverflow.com/a/23378064/588476
À luz dessa informação, talvez seja mais seguro usar a função da Apple CACurrentMediaTime
!
Também mach_timebase_info
comparei a chamada e ela leva aproximadamente 19ns no meu iPhone 6, então removi o código (não thread-safe) que estava armazenando em cache a saída dessa chamada.
#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;
}
Esteja ciente do risco potencial de estouro, dependendo da saída da chamada da base de tempo. Eu suspeito (mas não sei) que pode ser uma constante para cada modelo de iPhone. no meu iPhone 6 era 125/3
.
A solução usando CACurrentMediaTime()
é bastante trivial:
uint64_t getTickCount(void)
{
double ret = CACurrentMediaTime();
return ret * 1000;
}
mach_timebase_info()
redefinirá o passado mach_timebase_info_data_t
para {0,0}
antes de defini-lo para os valores reais, o que pode causar divisão por zero se o código for chamado de vários threads. Use em dispatch_once()
vez disso (ou CACurrentMediaTime
que seja apenas o tempo de conversão de segundos para segundos).
Para medições de tempo percise (como GetTickCount), consulte também mach_absolute_time e as perguntas e respostas desta Apple: http://developer.apple.com/qa/qa2004/qa1398.html .
use a função timeIntervalSince1970 da classe NSDate como abaixo:
double start = [startDate timeIntervalSince1970];
double end = [endDate timeIntervalSince1970];
double difference = end - start;
Basicamente, é isso que eu uso para comparar a diferença em segundos entre duas datas diferentes. verifique também este link aqui
As outras respostas estão corretas (com uma ressalva *). Eu adiciono esta resposta simplesmente para mostrar um exemplo 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.
}
No console do depurador, você vê algo assim:
DEBUG Method '-[XMAppDelegate getYourAffairsInOrder]' ran. Elapsed: 0.033827 seconds.
* Advertência: Como outros mencionados, use NSDate
para calcular o tempo decorrido apenas para fins casuais. Um desses objetivos pode ser o teste comum, o perfil bruto, no qual você deseja apenas uma idéia aproximada de quanto tempo um método está demorando.
O risco é que a configuração da hora atual do relógio do dispositivo possa mudar a qualquer momento devido à sincronização do relógio da rede. Portanto, o NSDate
tempo pode pular para frente ou para trás a qualquer momento.
fabs(...)
para obter o valor absoluto de um flutuador. Por exemplo.NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);