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

Joh*_*ers 9 macos cocoa objective-c

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

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

[[NSRunLoop currentRunLoop] addTimer:pingTimer forMode:NSDefaultRunLoopMode];
Run Code Online (Sandbox Code Playgroud)

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

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

这不是我期望发生的事情,因为我称之为"initWithFireDate".

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

Joh*_*ers 25

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

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                                                       selector:@selector(resetTimers:)         
                                                           name:NSWorkspaceDidWakeNotification
                                                         object:nil];
Run Code Online (Sandbox Code Playgroud)