Acabei de terminar com o meu aplicativo e o teste beta encontrou um bug na parte do cronômetro … O cronômetro usa um nstimer para fazer a contagem e tem uma tabela para armazenar voltas, mas quando a mesa de voltas é rolada, o relógio para ou pausa e não compensa o tempo perdido.
Isso foi stalling foi eliminado usando:
startingTime = [[NSDate date] timeIntervalSince1970];
para calcular o tempo decorrido.
mas eu ainda estou usando o NSTimer para acionar a cada 0,1 segundos e isso significa que a rolagem ainda impede o timer, mesmo que o tempo decorrido será atualizado corretamente no final … e comparando isso com o cronômetro da Apple, isso me faz pensar se o cronômetro tem um thread separado apenas para a contagem do tempo decorrido. Alguém sabe se é assim que é feito?
Agora, usar o tempo desde a Época está funcionando bem em um sentido, mas complica a questão de iniciar, parar e reiniciar o cronômetro
quando o relógio é parado, o tempo é armazenado e usado para calcular um deslocamento para quando o relógio é reiniciado, mas parece haver alguma latência introduzida e o tempo salta à frente visivelmente quando o relógio é reiniciado.
Qualquer pensamento em relação à causa raiz ou a uma solução seria muito apreciado.
A resposta do bbum fornece uma maneira melhor de projetar seu aplicativo, mas se você quiser que seu timer seja acionado, independentemente de o usuário estar manipulando a UI ou não, você precisará adicioná-la ao modo de rastreamento do runloop.
Supondo que você esteja desenvolvendo para o iPhone, esse modo é UITrackingRunLoopMode
. Se você está desenvolvendo para o Mac, existe um NSEventTrackingRunLoopMode
com o mesmo nome.
NSRunLoop *runloop = [NSRunLoop currentRunLoop]; NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(myTimerAction:) userInfo:nil repeats:YES]; [runloop addTimer:timer forMode:NSRunLoopCommonModes]; [runloop addTimer:timer forMode:UITrackingRunLoopMode];
Se o loop de events não estiver em execução, todos os timers não serão triggersdos até que o loop de events possa ser executado novamente. Mesmo que o loop de events não seja bloqueado, não é garantido que o timer seja triggersdo exatamente no intervalo configurado. Se os seus horários foram baseados inteiramente em triggersdores de timers, a quantidade de erros aumentará com o tempo.
Você precisa acompanhar a duração separadamente do disparo dos timers. Cada vez que um timer triggers, recalcule sua duração e volte a exibir.
Para um tipo de configuração iniciar / pausar / reiniciar / parar, você geralmente deseja:
pegue o tempo após o início (como uma instância NSDate ou como um valor NSTimeInterval)
após a pausa ou parar, agarre o tempo após a pausa / parada. Subtraia a hora de início a partir desta hora e você terá a duração do intervalo
ao reiniciar, agarre o tempo após a reboot, mas também mantenha a duração já decorrida
ao pausar / parar, agarre a hora em pausa / parada e adicione a duração já decorrida
Em geral, fazer tudo isso com valores NSTimeInterval – que são apenas duplos – é mais fácil. No entanto, se você precisar acompanhar o momento real no momento em que os events aconteceram, use as instâncias do NSDate.