2011-10-06 61 views
4

我正在使用NSTimer来更新显示每分钟当前时间的标签。我在一个完整的分钟日期(例如2:23:00而不是2:22:17)启动计时器。问题是NSTimer似乎工作不正确,这意味着它有时会引发太早(导致(例如)2:23 PM,实际上是2:24 PM)。NSTimer不准确?

是否有任何修复/解决方法?

编辑:这就是我如何启动定时器:

NSTimer *clockTimer = [[NSTimer alloc] initWithFireDate:[NSDate nextFullMinuteDate] 
               interval:60.0 
               target:self 
               selector:@selector(updateClocks:) 
               userInfo:nil 
               repeats:YES]; 
[[NSRunLoop currentRunLoop] addTimer:clockTimer 
          forMode:NSDefaultRunLoopMode]; 
[clockTimer release]; 

顺便说一句,我曾尝试加入几毫秒到火日期,这似乎帮助,但它看起来就像找到被击中适当的间隔添加-and错过。编辑2:好吧,所以我手动设置我的计时器在一分钟后0.05秒发射,然后在60.0秒后再次发射。现在,这里是我在调用的方法登录:

0.048728 
0.047153 
0.046484 
0.044883 
0.043103 

正如你所看到的,NSTimer实际上并未使用60秒的时间间隔,但略短的一个。

+0

很难说不知道如何计算间隔并启动计时器 – hamstergene

+0

如何计算'nextFullMinuteDate'? –

+0

@PeterHosey:look [here](http://pastebin.com/ZsXWfM0p) – ryyst

回答

0

那么,我只是写了我自己的小NSTimer包装,叫做MinuteTimer来“解决”这个问题。我上传了pastebin。这个想法是重置定时器,只要它经常发射得太快以至于日期风险显示不正确。

由于这是管道式磁带编程,我仍然渴望听到其他答案!

0

我假设你从当前时间开始,然后每当NSTimer关闭时,你将一分钟添加到原始时间,然后显示它。你应该对你的计时器做什么:每当计时器关闭时,重新读取当前时间并显示它。

+0

不,我总是重读当前时间并显示它。 – ryyst

+0

您还应该每分钟更频繁地启动计时器。 – MusiGenesis

+0

因为计时器似乎太早启动。像在2:23:59.999而不是2:24:00。至少这是我认为正在发生的事情。 – ryyst

0

您应该将您的计时器设置为每秒钟而不是每分钟。但不要每秒更新你的标签。只需比较当前时间的新分钟数是否与上次更新标签的分钟数不同,如果是,则更新标签。

+1

对不起,但这听起来效率很低。 – ryyst

1

NSTimer docs

计时器不是实时的机构;只有在添加了定时器的 运行循环模式之一运行并且能够 检查定时器的触发时间是否已经过去时才会触发。由于典型的运行循环管理各种输入源,所以有效的分辨率为 ,定时器的时间间隔被限制在大约50-10 毫秒的量级。如果在长时间标注或 期间发生定时器的触发时间,而运行循环处于未监控定时器的模式,则在下一次运行循环检查定时器之前,定时器不会触发。因此,计时器触发的实际时间可以在预定的触发时间之后的相当长的一段时间内为 。

这意味着NSTimer是非常不准确的。

如果您编写“秒表”,则可以使用NSTimer向用户显示结果,而NIRTimer(我最喜欢的类之一)会记录时间。此概述如下:

NIRTimer *nirTimer; 
NSTimer *timer; 

- (void)start { 
    nirTimer = [[NIRTimer alloc]init]; 
    timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES]; 
    [nirTimer start]; 

- (void)timerFired:(NSTimer *)timer { 
    [self displayTimeToUser:[nirTimer seconds]]; 
} 

在上面的代码中,NSTimer可能不准确,但是精确的时间由NIRTimer,其每0.01秒显示给用户保持。

如果你确实需要特定的代码运行在一个确切的时间,我已经找到了最好的解决方案是使用NSThreadusleep()

BOOL timerRunning; 

- (void)start { 
    timerRunning = YES; 
    [NSThread detachNewThreadSelector:@selector(timer) toTarget:self withObject:nil]; //make a new thread 
} 

- (void)timer { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; //Make an autorelease pool since we're in a new thread 
    NIRTimer *timer = [[NIRTimer alloc]init]; //Make an NIRTimer 
    while (timerRunning) { 
     [timer reset]; 
     [timer start]; 
     [self doSomething]; 
     usleep(10000 - [timer microseconds]); //Wait for .01 seconds which is 10000 microseconds (a microsecond is 1/1000000th of a second) - the time it took to accomplish whatever we were doing 
    } 
    //Clean up 
    [timer release]; 
    [pool release]; 
} 

在这种情况下,设置timerRunningNO停止定时器。如果您尝试执行的操作不是线程安全的,您可能还想使用[self performSelectorOnMainThread:@selector(doSomething) withObject:nil waitUntilDone:NO]而不是[self doSomething]

欲了解更多精彩的穿线世界,请看Threading Programming Guide