我正在编写一个 Cocoa OS X (Leopard 10.5+) 最终用户程序,该程序使用时间戳来计算屏幕上显示内容的统计时间。当程序运行时,使用重复的 NSTimer 定期计算时间。 [NSDate date] 用于捕获时间戳, 开始结束. 。以秒为单位计算两个日期之间的差异是微不足道的。

如果最终用户或 ntp 更改系统时钟,就会出现问题。 [NSDate date] 依赖于系统时钟,所以如果它改变了, 结束 变量将相对于 开始, ,严重扰乱时间计算。我的问题:

1.如何准确计算之间的时间 开始结束, ,以秒为单位,即使系统时钟中途更改?

我想我需要一个不变的时间参考点,这样我就可以计算从那时起已经过去了多少秒。例如,系统正常运行时间。10.6有 - (NSTimeInterval)systemUptime, , 部分 NSProcessInfo, ,提供系统正常运行时间。但是,这不起作用,因为我的应用程序必须在 10.5 中运行。

我尝试过使用 NSTimer 创建时间计数器,但这并不准确。NSTimer 有几种不同的运行模式,并且一次只能运行一种。NSTimer(默认情况下)被放入 默认 运行模式。如果用户开始操作 UI 的时间足够长,就会进入 NSEventTrackingRunLoopMode 并跳过 默认 运行模式,这可能导致 NSTimer 触发被跳过,使其成为一种不准确的秒数计数方式。

我还考虑过创建一个单独的线程(NSRunLoop)来运行 NSTimer 秒计数器,使其远离 UI 交互。但我对多线程非常陌生,如果可能的话我想远离它。另外,我不确定如果 CPU 被另一个应用程序(Photoshop 渲染大图像等)固定,这是否能正常工作,导致我的 NSRunLoop 被搁置足够长的时间以弄乱它的NSTimer。

我很感激任何帮助。:)

有帮助吗?

解决方案 3

我找到了一种方法,使用<CoreServices/CoreServices.h>中提供的 UpTime() C函数来完成此操作。这将返回绝对时间(特定于CPU),可以轻松转换为持续时间(毫秒或纳秒)。详细信息: http://www.meandmark.com/timingpart1.html (查看部分内容) 3为UpTime)

我无法正常工作,可能是由于我对此缺乏了解,而且无法在网上找到很多关于它的文档。它似乎与mach_absolute_time()同时占用,但将其转换为双重让我目瞪口呆。

UpTime()确实有效,但仅在应用程序接收NSEvents时才有效。如果应用程序进入前台,它将不会接收事件,并且[[NSApp currentEvent] timestamp]将简单地继续在NSTimer触发方法中一次又一次地返回相同的旧时间戳,直到最终用户决定再次与应用程序交互。

感谢Marc和Mike的所有帮助!你们两个肯定都把我送到了正确的方向,导致了答案。 :)

其他提示

根据驱动此代码的原因,您有 2 个选择:

  • 对于绝对精度,请使用 mach_absolute_time(). 。它将准确给出您调用该函数的点之间的时间间隔。
  • 但在 GUI 应用程序中,这实际上通常是不可取的。相反,您想要的是之间的时差 事件 开始和结束你的持续时间。如果是这样,比较一下 [[NSApp currentEvent] timestamp]

好的,所以这是一个很长的镜头,但你可以尝试在Snow Leopard中实现某种类似NSSystemClockDidChangeNotification的东西。

所以请在这里忍受,因为这是一个奇怪的想法,绝对是非确定性的。但是,如果你的程序持续时间内有一个监视程序线程怎么办?每隔n秒,该线程将读取系统时间并存储它。为了争论,我们只需要5秒钟。因此,每隔5秒,它会将先前的读数与当前系统时间进行比较。如果有一个<!>“足够大的<!>”;差异(<!>“足够大<!>”需要肯定大于5,但太多更大,以解决进程调度和线程优先级的非确定性)发布通知,表示时间有重大变化。你需要玩弄模糊构成<!>“足够大的<!>”的值。 (或者足够小,如果时钟被重置为更早的时间)以满足您的准确性需求。

我知道这有点像hacky,但除非有任何其他解决方案,你怎么看?可能,或类似的东西,解决你的问题?

修改

好的,所以你修改了原来的问题,说你不想使用看门狗线程,因为你不熟悉多线程。我理解做一些比你习惯更高级的事情的恐惧,但这可能最终成为唯一的解决方案。在这种情况下,您可能需要阅读一些内容。 =)

是的,我知道像Photoshop那样将垃圾从处理器中剔除是一个问题。另一个(甚至更复杂的)解决方案是,而不是拥有监视器线程,而是拥有一个具有最高优先级的独立监视程序进程,因此它对处理器更具免疫力挂。但同样,这变得非常复杂。

最终修改

为了完整起见,我将把所有其他想法留在上面,但似乎使用系统的正常运行时间也是处理这个问题的有效方法。由于[[NSProcessInfo processInfo] systemUptime]仅适用于10.6+,您只需拨打mach_absolute_time()即可。要访问该功能,只需#include <mach/mach_time.h>。该值应与NSProcessInfo返回的值相同。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top