当iOS 7设备进入睡眠模式时,clock_get_time/mach_absolute_time停止更新。

7
我的应用程序使用mach_absolute_time来计算自上次触摸事件以来的滴答数,并在超过10分钟的空闲时间限制后将用户注销。
这在iOS 6上运行得很好,但我注意到在iOS 7上它的行为不正确。具体来说,当iOS 7设备(使用电池)未连接电源时,在此行之后,设备似乎停止递增其滴答声,随着无操作时间的增加,设备会进入睡眠状态: powerd [47]:Sleep:Using BATT(Charge:99%)
因此,当我在10分钟后唤醒设备并使用mach_absolute_time计算滴答数时,差异显示仅为5分钟(实际上已经过去了10分钟)。
奇怪的是,当设备连接到电源时,一切都正常工作,滴答声继续运行。当连接时,控制台日志中从不显示设备正在进入睡眠状态(尽管屏幕确实关闭,并且在视觉上的行为与断开连接时相同)。
我也尝试使用clock_get_time,但遇到了同样的问题。
在iOS 7中是否有什么可以做的事情,以使Mach绝对时间在设备进入睡眠状态时继续运行?我不想使用[[NSDate date] timeIntervalSince1970],因为用户可以操纵系统时间并绕过此功能。
感谢您的任何见解。
2个回答

2
原来mach_absolute_time()的默认行为是在设备进入睡眠状态时停止计时。在iOS 6中,我可以使用beginBackgroundTaskWithExpirationHandler将应用程序放入后台并将挂起时间延长10分钟。然而,在iOS 7中,此项最长允许时间已被限制在3分钟(通过调用backgroundTimeRemaining发现)。这就是为什么我在iOS 7上看到时钟停止,但在iOS 6上没有看到的原因。

今天偶然发现了这个答案,看起来很有希望。

- (time_t)uptime {
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    time_t now;
    time_t uptime = -1;
    (void)time(&now);
    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) {
        uptime = now - boottime.tv_sec;
    }
    return uptime;
}

当设备处于睡眠状态时,time()函数会继续递增,但这个值可以被操作系统或用户所修改。然而,内核的boottime(记录系统上次启动时间的时间戳)在系统时钟改变时也会发生变化,因此尽管这两个值都不是固定的,它们之间的偏移量是固定的。


那么有没有办法解决并允许后台线程在iOS7上继续运行呢? - Mrunal
很酷,你也可以在这里找到类似的源代码:https://dev59.com/4GHVa4cB1Zd3GeqPkCu3#9744686 - Danra
@Mrunal 我尝试了一些方法,但似乎这是一个无法扩展的硬性限制。除了WWDC视频之外,文档对此的描述不够详细。这是我找到的最好的提到后台时间减少的链接:https://developer.apple.com/library/ios/releasenotes/General/RN-iOSSDK-7.0/#//apple_ref/doc/uid/TP40013202-CH1-SW84 - Jay
您建议在这里进行编辑:https://dev59.com/NmQo5IYBdhLWcg3wBLYo#16398904。如果您认为某人的代码有问题,并且该用户最近访问过,请在帖子上留下评论。 - Bill Woodger

1

现在你可以使用clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)来包括睡眠时间。在Swift中:

import Foundation

let elapsed_time_nanos = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)

我在苹果官网上找不到那个函数的文档,但是mach_continuous_time的文档中提到了它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接