当runloop被阻止时,NSTimer不会触发

时间:2010-01-03 18:32:28

标签: cocoa nsdate nstimer

我刚刚完成我的应用程序和beta测试发现秒表部分的错误... 秒表使用nstimer进行计数,并有一个用于存储圈数的表,但是当滚动表时,手表会停止或暂停,并且不能弥补丢失的时间。

通过使用:

消除了失速
startingTime = [[NSDate date] timeIntervalSince1970];

计算经过的时间。

但是我仍然使用NSTimer来触发每0.1秒,这意味着滚动仍然会使定时器停止,即使经过的时间最终会正确更新...并将其与Apple秒表进行比较它会让我想知道那个秒表是否有一个单独的线程只是为了计算经过的时间。有谁知道这是怎么做的?

现在,使用自大纪元以来的时间在某种意义上运作良好,但它使启动,停止和&重新启动秒表

当手表停止时,存储时间并用于计算手表重启时的偏移量,但似乎有一些延迟时间,并且重新启动手表时时间会明显跳跃。

对于根本原因或解决方案的任何想法都将非常感激。

2 个答案:

答案 0 :(得分:47)

bbum的答案提供了一种更好的方法来设计你的应用程序,但如果你想让你的计时器触发,无论用户是否正在操作UI,你都需要将它添加到runloop的跟踪模式。

假设您正在为iPhone开发,该模式为UITrackingRunLoopMode。如果您正在为Mac开发,则会有类似名称NSEventTrackingRunLoopMode

NSRunLoop *runloop = [NSRunLoop currentRunLoop];
NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(myTimerAction:) userInfo:nil repeats:YES];
[runloop addTimer:timer forMode:NSRunLoopCommonModes];
[runloop addTimer:timer forMode:UITrackingRunLoopMode];

答案 1 :(得分:22)

如果事件循环未运行,则在事件循环再次运行之前,任何计时器都不会触发。即使事件循环不是阻塞,也不能保证定时器在其配置的间隔内正好触发。如果你的时间完全基于计时器开火,那么错误的数量会随着时间的推移而增长。

您需要与定时器的触发分开跟踪持续时间。每次计时器触发时,重新计算持续时间并重新显示。

对于开始/暂停/重启/停止类型的设置,您通常希望:

  • 在启动时获取时间(作为NSDate实例或作为NSTimeInterval值)

  • 暂停或停止后,暂停/停止时抓住时间。从此时间减去开始时间,并且您有间隔的持续时间

  • 重启后,抓住重启时的时间,但也要保持已经过的持续时间

  • 暂停/停止时,抓住暂停/停止的时间并添加已经过的持续时间

一般来说,使用NSTimeInterval值(只是双倍)来完成所有这些操作是最简单的。但是,如果您需要跟踪事件发生的实际时刻,请改用NSDate实例。