10

我正在设置一个计时器以在将来运行特定功能,如下所示:

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

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

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

在未来安排几分钟时,我观察到计时器仍然会响起,但它似乎会在特定的分钟数后响起。假设我将计时器安排在未来 5 分钟的日期,然后我将时钟调快 1 小时,计时器实际上会在 5 分钟后触发,但是由于我将时钟调快 1 小时,因此它触发的时间不再对齐与它预定开火的时间。

这不是我所期望的,因为我称之为“initWithFireDate”。

尽管所有这一切对我来说似乎都是错误的(对其他人来说可能是一个有趣的观察),但问题是我如何确保计时器一旦注意到它的触发日期已经过去就触发(即我如何确保我的当有人将时钟移过预定的触发日期时,计时器将触发)。

4

1 回答 1

26

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

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

如果您的系统进入睡眠状态(或您的应用程序被挂起),您的计时器将不再计时。当您的系统唤醒(或您的应用程序变为活动状态)时,它将继续计时,但这意味着您的计时器现在不会在原始的“FireDate”处执行。相反,它将在“FireDate”+(您的计算机睡眠时间)执行。

同样,如果用户更改系统时间,这不会以任何方式影响计时器。如果计时器计划在未来 8 小时后触发,它将在触发前继续计时 8 小时。

如果您希望计时器在遥远的将来的特定时钟时间触发,您需要确保您的应用程序收到以下事件的通知:

  1. 从睡梦中醒来
  2. 系统时间变化

当任何这些事件发生时,您将需要使任何现有计时器无效并调整。

/* 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];
于 2013-05-16T21:33:21.170 回答