当手动设置时钟时,NSTimer缺少开火日期

时间:2013-05-15 20:37:56

标签: objective-c macos cocoa

我正在设置一个计时器,以便将来运行一个特定的功能:

pingTimer = [[NSTimer alloc] initWithFireDate:pingAtDate
                                     interval:0
                                       target:self
                                     selector:@selector(ping:)
                                     userInfo:nil
                                      repeats:NO];

[[NSRunLoop currentRunLoop] addTimer:pingTimer forMode:NSDefaultRunLoopMode];

日期约为未来一周,因此出于测试目的,我(和其他人)已将系统时钟设置为8天,以确保指定的事件发生。问题是它不会发生。

在将来安排几分钟时,我发现计时器仍然会关闭,但在特定的分钟数后它似乎会熄灭。假设我将计时器安排在将来5分钟的日期,然后我将时钟设置为1小时,计时器确实在5分钟后启动,但是因为我将时钟向前设置1小时它发射的时间不再对齐计划在那里开火的时间。

这不是我期望发生的事情,因为我称之为“initWithFireDate”。

虽然所有这些对我来说似乎都是错误的(并且对其他人来说可能是一个有趣的观察)但问题是我如何确保计时器一旦发现它的火灾日期已经过去就会触发(即我如何确保当有人将时钟移动超过预定的发射日期时,我的计时器将会启动。)

1 个答案:

答案 0 :(得分:25)

还有一些好的评论,但没有完整的答案。我将在这里将所有相关细节汇总在一起。

NSTimer不是时钟机制。当您设置“FireDate”时,您无法确定计时器是否会在该日期实际触发。你实际上是在告诉计时器在开火前运行特定的时间。这段时间是将计时器添加到运行循环和计划计时器触发的日期之间的差异。

如果您的系统进入休眠状态(或您的应用程序暂停),您的计时器将不再打勾。当系统唤醒(或您的应用程序变为活动状态)时,它将恢复滴答,但这意味着您的计时器现在不会在原始“FireDate”上执行。相反,它将在“FireDate”+(计算机处于睡眠状态的时间)执行。

同样,如果用户更改系统时间,则不会以任何方式影响计时器。如果计时器计划在将来8小时开火,它将在发射之前继续缩短8小时的时间。

如果您希望在不久的将来在特定时钟时间点击计时器,则需要确保您的应用程序收到以下事件的通知:

  1. 从睡梦中醒来
  2. 系统时间更改
  3. 当发生任何这些事件时,您需要使任何现有的计时器无效并进行调整。

    /* If the clock time changed or we woke from sleep whe have to reset these long term timers */
    - (void) resetTimers: (NSNotification*) notification
    {
        //Invalidate and Reset long term NSTimers
    }
    

    您可以观察以下通知,以便在这些事件发生时得到通知。

    [[NSNotificationCenter defaultCenter] addObserver:self                          
                                             selector:@selector(resetTimers:)               
                                                 name:NSSystemClockDidChangeNotification            
                                               object:nil];
    
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                                                           selector:@selector(resetTimers:)         
                                                               name:NSWorkspaceDidWakeNotification
                                                             object:nil];