当 runloop 被阻塞时 NSTimer 不会触发

发布于 2024-08-16 20:25:54 字数 517 浏览 1 评论 0原文

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

通过使用以下方法可以消除这种停顿:

startingTime = [[NSDate date] timeIntervalSince1970];

计算经过的时间。

但我仍然使用 NSTimer 每 0.1 秒触发一次,这意味着滚动仍然会停止计时器,即使经过的时间最终会正确更新......并将其与 Apple 秒表进行比较,这让我想知道是否秒表有一个单独的线程,仅用于计算经过的时间。有谁知道这是如何完成的吗?

现在,从某种意义上说,使用纪元以来的时间效果很好,但它使开始、停止和结束的问题变得复杂。 当手表停止时重新启动秒表,

时间被存储并用于计算手表重新启动时的偏移量,但似乎引入了一些延迟,并且当手表重新启动时时间明显向前跳跃。

任何有关根本原因或解决方案的想法将不胜感激。

I am just about finished with my app and beta testing found a bug in the stopwatch portion...
The stopwatch uses an nstimer to do the counting and has a table for storing laps, but when the lap table is scrolled the watch stops or pauses and does not make up for the lost time.

This was stalling was eliminated by using:

startingTime = [[NSDate date] timeIntervalSince1970];

to calculate the elapsed time.

but I am still using the NSTimer to trigger every 0.1 secs and that means that the scrolling still stalls the timer even though the elapsed time will be updated correctly in the end... and comparing this to the Apple stopwatch it makes me wonder if that stopwatch has a separate thread just for the elapsed time counting. Does anyone know if that is how it is done?

Now, using the time since the Epoch is working well in one sense, but it complicates the matter of starting, stopping, & restarting the stopwatch

when the watch is stopped the time is stored and used to calculate an offset for when the watch is restarted, but there seems to be some latency introduced and the time jumps ahead visibly when the watch is restarted.

Any thoughts toward the root cause or a solution would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毁梦 2024-08-23 20:25:54

bbum 的答案提供了一种更好的方法来设计应用程序,但是如果您希望无论用户是否正在操作 UI,计时器都会触发,您需要将其添加到运行循环的跟踪模式中。

假设您正在针对 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];

bbum's answer provides a better way to design your application, but if you want your timer to fire regardless of whether the user is manipulating the UI or not you'll need to add it to the tracking mode of the runloop.

Assuming that you're developing for the iPhone, that mode is UITrackingRunLoopMode. If you're developing for the Mac there is a similarly named 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];
毁梦 2024-08-23 20:25:54

如果事件循环未运行,则在事件循环再次运行之前,任何计时器都不会触发。即使事件循环没有被阻止,计时器也不能保证按照其配置的时间间隔触发。如果您的计时完全基于计时器触发,则错误量将随着时间的推移而增加。

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

对于启动/暂停/重新启动/停止类型的设置,您通常需要:

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

  • 暂停或停止时,抓取暂停/停止时的时间。从这个时间减去开始时间,你就得到了

  • 重新启动时,抓取重新启动时的时间但也保留已经过去的持续时间

  • 在暂停/停止时,抓取暂停/停止时的时间并

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

If the event loop isn't running, any timers will not fire until the event loop can run again. Even if the event loop isn't block, the timer isn't guaranteed to fire at exactly its configured interval. If your timings were based entirely on timers firing, the amount of error will grow over time.

You need to keep track of the duration separately from the firing of the timers. Each time a timer fires, recalculate your duration and redisplay.

For a start/pause/restart/stop type of setup, you generally want to:

  • grab the time upon start (either as an NSDate instance or as an NSTimeInterval value)

  • upon pause or stop, grab the time upon pause/stop. Subtract the start time from this time and you have the interval's duration

  • upon restart, grab the time upon restart but also keep around the already elapsed duration

  • upon pause/stop, grab the time at pause/stop and add the already elapsed duration

In general, doing all of this with NSTimeInterval values -- which are just doubles -- is easiest. However, if you need to keep track of the actual moment in time when the events happened, use NSDate instances instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文