【问题标题】:iOS: recreating countdown timers after clock change?iOS:时钟更改后重新创建倒数计时器?
【发布时间】:2011-08-22 18:26:51
【问题描述】:

我正在开发一个使用 NSTimer 进行倒计时的 iOS 应用。这很容易被用户篡改:例如,如果用户退出应用程序,手动关闭应用程序,更改设备时钟,然后返回,则必须重新创建计时器。另一种情况:用户锁定设备,进入低功耗模式(需要重新创建计时器),并且在再次打开游戏之前自动设置时钟。如果发生这种情况,我将无法准确确定应用程序关闭后经过了多长时间,因为设备时钟已更改。

Tl;dr:倒计时计时器有时必须在设备时钟更改后重新创建。这个问题一般是怎么处理的?

【问题讨论】:

  • 在任何人建议之前:我已经看到 mach_absolute_time() 大肆宣传,但是 a) 对于高级问题,它似乎是一种非常低级的方法,并且 b) 因为 AFAIK 它使用CPU 滴答测量时间,我想它不如石英钟准确。
  • 您想用最后一个已知时间重新创建计时器,还是想从头开始?如果您想使用最后一次重新创建它,那么也许您可以在应用即将更改状态时将时间保存到用户首选项,并在应用返回时从用户首选项中读取。
  • 我希望它看起来好像计时器在后台滴答作响,就像什么都没发生一样。示例:用户在还剩 10 秒时切换,并将时间更改为提前 1 小时。这需要用户 5 秒。当用户回来时,计时器应该说 5 秒。
  • 您需要时钟有多准确?通常,您需要在“applicationDidResignActive”等函数中保存计时器中剩余的时间和时间量,并在“applicationDidBecomeActive”上使用此数据创建一个新计时器。确切的实施应根据所需的准确性而有所不同。
  • 它不需要非常精确,只要合理——几秒钟内。我已经在 applicationDidResignActive 中保存了时间数据,但是如果系统时间发生变化,我无法测量程序处于非活动状态的时间。

标签: objective-c ios time timer


【解决方案1】:

任何时候您依赖系统时钟来获得准确的计时,您都会遇到麻烦,即使用户不是故意篡改时钟。通常,通过稍微增加或减少一秒的长度来校正时钟漂移,以使时钟在几分钟内重新回到对齐状态。如果您需要准确的计时,您可以使用mach_absolute_time() 之类的东西,它与系统正常运行时间而不是系统时钟有关,或者您可以使用 Grand Central Dispatch。 dispatch_after() 函数采用 dispatch_time_t,可以使用挂钟时间(例如系统时钟)或相对于 DISPATCH_TIME_NOW(忽略挂钟)的偏移量来表示。

【讨论】:

  • 我听说过 mach_absolute_time(),但是由于它使用 CPU 滴答而不是系统时钟来测量时间,所以它的准确度不会大大降低吗?至于 GCD,我想保留与旧 iOS 版本的兼容性。
  • mach_absolute_time() 是您可以获得的最准确的计时器。这不是对 CPU 工作的某种测量(无论如何这没有任何意义,CPU 运行时钟信号,而不是相反)。您可能会感到困惑,因为mach_absolute_time() 返回一个称为“依赖于 CPU”的值,但这并不意味着它不准确或不可靠。这只是意味着它需要转换成你可以使用的单位。
  • 感谢您的澄清——我认为我对计时的工作原理有一些了解。 mach_absolute_time() 是“规范”计时功能吗?在 4.2 中,定义了三个 time.h 头文件,Apple 的“Miscellaneous Kernel Services”文章 (developer.apple.com/library/mac/#documentation/Darwin/…) 谈到了更多的几个计时函数。
  • 那篇文章讨论的是在内核中使用的函数。您不是在编写在内核中执行的代码。 mach_absolute_time() 是这里的合适函数,不过您也可以根据需要使用 CACurrentMediaTime(),因为该函数基于 mach_absolute_time()
  • 谢谢!那时我可能会选择 CACurrentMediaTime(),因为在稍高的抽象级别上工作会很好。
【解决方案2】:

供将来参考,关于 OSX(以及 iOS)中不同的计时系统:

一种衡量任何操作速度的方法,包括启动时间, 是使用系统例程在开始时获取当前时间和 操作结束。一旦你有两个时间值,你可以采取 差异并记录结果。

这种技术的优势在于它可以让您测量 特定代码块的持续时间。 Mac OS X 包括几个 获取当前时间的不同方法:

  • mach_absolute_time 读取 CPU 时基寄存器,是 其他时间测量功能的基础。
  • 核心服务 UpTime 功能提供纳秒级分辨率 用于时间测量。
  • BSD gettimeofday 函数(在<sys/time.h> 中声明)提供
    微秒分辨率。 (注意,这个函数会产生一些开销,但是 对于大多数用途来说仍然是准确的。)
  • 在 Cocoa 中,您可以创建一个 NSDate 对象,当前时间为 开始操作然后使用
    timeIntervalSinceDate:获取时间差的方法。

来源:Launch Time Performance Guidelines, "Gathering Launch Time Metrics"

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2019-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-13
  • 2020-12-12
  • 1970-01-01
相关资源
最近更新 更多