Cocoa NSTimer不准确?

Cocoa NSTimer不准确?,cocoa,nstimer,Cocoa,Nstimer,我正在使用NSTimer更新一个标签,该标签显示每分钟的当前时间。我在整分钟的日期(例如2:23:00而不是2:22:17)启动计时器。问题是,NSTimer似乎工作不准确,这意味着它有时发射得太早(这导致(例如)下午2:23,而实际上是下午2:24) 是否有任何修复/解决方法 编辑:以下是我如何启动计时器: NSTimer *clockTimer = [[NSTimer alloc] initWithFireDate:[NSDate nextFullMinuteDate]

我正在使用
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秒的时间间隔,而是稍微短一点的时间间隔。

我假设您从当前时间开始,然后每次
NSTimer
发生故障时,您都会在原始时间上增加一分钟,然后显示它。您应该使用计时器:每次计时器关闭时,重新读取当前时间并显示它。

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

好吧,我刚刚编写了自己的小
NSTimer
包装,名为
MinuteTimer
,以“解决”问题。我已经上传到了。这样做的目的是,每当计时器启动得太快以至于日期有可能被错误显示时,就重置计时器

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

来自:

计时器不是实时机制;只有当其中一个 已添加计时器的运行循环模式正在运行且可启用 检查计时器的启动时间是否已过。因为各种各样的 输入源一个典型的运行循环管理,有效解决 计时器的时间间隔限制在50-100之间 毫秒。如果计时器的触发时间发生在长调用或 当运行循环处于不监视计时器的模式时 直到下次运行循环检查计时器时,计时器才会启动。 因此,计时器可能触发的实际时间可以是 预定点火时间后的一段重要时间

这意味着
NSTimer
非常不准确

如果编写“秒表”,可以使用
NSTimer
向用户显示结果,同时(我最喜欢的课程之一)跟踪时间。这一点概述如下:

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]];
}
在上面的代码中,
n计时器
可能不准确,但准确的时间由
n计时器
保持,它每隔
0.01
秒向用户显示一次

如果您确实需要在准确的时间运行特定的代码,我找到的最佳解决方案是使用
NSThread
usleep()

在这种情况下,将
timerRunning
设置为
NO
以停止计时器。如果您尝试执行的操作不是线程安全的,您可能还希望使用对象为nil waitUntilDone:NO的
[self-performselectornmainthread:@selector(doSomething)]
而不是
[self-doSomething]


有关线程的精彩世界的更多信息,请查看。

您还应该更频繁地启动计时器,而不是每分钟启动一次。因为计时器似乎启动得太早。比如2:23:59.999而不是2:24:00。至少我认为是这样的。对,所以有时候你的时间会减少1分钟,最多1分钟。尝试每秒钟或每10秒(或任何你确定的最小可接受错误)启动一次计时器。如果不知道你是如何计算时间间隔和开始计时的,很难说你是如何计算
nextFullMinuteDate
?@PeterHosey:look@PeterHosey:allow,查看我在下面的答案中编写和发布的
MinuteTimer
课程。这应该可以让您快速创建SSCCE。抱歉,这听起来效率很低。
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];
}