我正在使用NSTimer
更新标签,以显示每分钟的当前时间。我在完整的分钟日期(例如2:23:00而不是2:22:17)开启计时器。问题是NSTimer
似乎工作不准确,这意味着它有时会过早发生(导致(例如)下午2:23,当它真的是下午2:24)。
是否有任何修复/解决方法?
编辑:以下是我启动计时器的方法:
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];
顺便说一句,我已经尝试在火灾日期添加几毫秒,这似乎有所帮助,但看起来找到一个合适的间隔来添加就是命中注定。
编辑2:好的,所以我手动设置我的计时器在一整分钟后开始0.05秒,然后在60.0秒后再次开始。现在这是我在被调用方法中登录的内容:
0.048728
0.047153
0.046484
0.044883
0.043103
正如您所看到的,NSTimer
实际上并不使用60秒的时间间隔,而是稍微短一些。
答案 0 :(得分:1)
来自NSTimer
docs:
计时器不是实时机制;它只在其中一个发射时发射 已添加计时器的运行循环模式正在运行且能够运行 检查计时器的开火时间是否已经过去。因为各种各样 输入源一个典型的运行循环管理,有效的分辨率 计时器的时间间隔限制在50-100的量级 毫秒。如果在长时间标注期间发生计时器的发射时间或 当运行循环处于不监视计时器的模式时, 在下次运行循环检查计时器之前,计时器不会触发。 因此,计时器可能发射的实际时间可能是 在计划的射击时间之后很长一段时间。
这意味着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
每隔NSThread
秒向用户显示一次。
如果您确实需要在特定时间运行特定代码,我找到的最佳解决方案是使用usleep()
和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];
}
:
timerRunning
在这种情况下,请将NO
设置为[self performSelectorOnMainThread:@selector(doSomething) withObject:nil waitUntilDone:NO]
以停止计时器。如果您尝试做的事情不是线程安全的话,您可能还想使用[self doSomething]
代替{{1}}。
有关精彩线程世界的更多信息,请查看Threading Programming Guide。
答案 1 :(得分:0)
我假设您从当前时间开始,然后每次NSTimer
关闭时,您将原始时间添加一分钟然后显示。您应该对计时器执行的操作是:每次计时器关闭时,重新读取当前时间并显示该计时器。
答案 2 :(得分:0)
您应该将计时器设置为每秒触发而不是每分钟。但是不要每秒更新您的标签。只需比较当前时间的新分钟数是否与上次更新标签时的分钟数不同,如果是,则更新标签。
答案 3 :(得分:0)
好吧,我刚刚编写了自己的小NSTimer
包装器,名为MinuteTimer
来解决问题。我已将其上传到pastebin。这个想法是在计时器发生得太快时重置计时器,以免日期冒险显示错误。
由于这是管道编程,我仍然渴望听到其他答案!