我认为DispatchTime和DispatchWallTime之间的区别与应用程序是否被暂停或设备屏幕是否被锁定有关:DispatchTime应该暂停,而DispatchWallTime应该继续运行,因为真实的世界中的时钟一直在运行。
所以我写了一个小的测试应用程序:
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
print("backgrounding the app, starting timers for 60 seconds", Date())
DispatchQueue.main.asyncAfter(deadline: .now() + 60) {
print("deadline 60 seconds ended", Date())
}
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 60) {
print("wallDeadline 60 seconds ended", Date())
}
}
func applicationWillEnterForeground(_ application: UIApplication) {
print("app coming to front", Date())
}
}
我在我的设备上运行了应用程序。我将应用程序置于后台,等待了一段时间,然后将应用程序带到前台。有时候“等一会儿”包括关掉屏幕。我得到了这样的结果:
backgrounding the app, starting timers for 60 seconds 2018-08-15 17:41:18 +0000
app coming to front 2018-08-15 17:41:58 +0000
wallDeadline 60 seconds ended 2018-08-15 17:42:24 +0000
deadline 60 seconds ended 2018-08-15 17:42:24 +0000
backgrounding the app, starting timers for 60 seconds 2018-08-15 17:42:49 +0000
app coming to front 2018-08-15 17:43:21 +0000
wallDeadline 60 seconds ended 2018-08-15 17:43:55 +0000
deadline 60 seconds ended 2018-08-15 17:43:55 +0000
deadline
计时器触发之前的延迟没有我预期的那么长:这是6秒超过60秒的最后期限,即使我“睡”的应用程序相当长的时间比这。但更令人惊讶的是,两个计时器在同一时刻发射。
那么,wallDeadline
在iOS上的功能与deadline
有什么不同呢?
2条答案
按热度按时间0x6upsns1#
The Dreams Wind的回答没有错,但我想更准确地理解这些API。这是我的分析。
DispatchTime
下面是
DispatchTime.init
上面的评论:所以
DispatchTime
基于mach_absolute_time
。什么是mach_absolute_time
?它在mach_absolute_time.s
中定义。每种CPU类型都有单独的定义,但关键是它在类似x86的CPU上使用rdtsc
,并在ARM上读取CNTPCT_EL0
寄存器。在这两种情况下,它都得到一个单调增加的值,并且只有在处理器没有处于足够深的睡眠状态时才增加。请注意,即使设备看起来处于睡眠状态,CPU也不一定睡眠得足够深。
DispatchWallTime
在
DispatchWallTime
的定义中没有类似的有用注解,但是我们可以看看它的now
方法的定义:然后我们可以参考the definition of
dispatch_walltime
:当
inval
为nil时,它调用_dispatch_get_nanoseconds
,所以let's check that out:POSIX
CLOCK_REALTIME
时钟因此,它是基于时间的共同理念,如果您在设置(或Mac上的系统偏好设置)中更改设备的时间,它将发生变化。神秘的六秒钟
你说你的计时器响了
超过60秒期限6秒
我们来看看这是怎么来的
asyncAfter(deadline:execute:)
和asyncAfter(wallDeadline:execute:)
都调用相同的C APIdispatch_after
。截止日期(或“时钟”)的类型与时间值沿着编码为dispatch_time_t
。dispatch_after
函数调用the internal GCD function_dispatch_after
,我在这里引用了它的一部分:_dispatch_timeout
函数可以在time.c
中找到。可以说,它返回当前时间和传递给它的时间之间的纳秒数。它根据传递给它的时间的时钟确定“当前时间”。因此,
_dispatch_after
获取在执行块之前等待的纳秒数。然后它计算leeway
作为该持续时间的十分之一。当它设置计时器的截止日期时,它将leeway
添加到您在中传递的截止日期。在你的例子中,
delta
大约是60秒(= 60 * 109纳秒),所以leeway
大约是6秒。因此,在调用asyncAfter
后大约66秒,块将被执行。az31mfrm2#
这个问题已经存在很长时间了,没有任何答案,所以我想给予一下,并指出我在实践中注意到的细微差异。
DispatchTime应该暂停,而DispatchWallTime应该继续运行,因为真实的世界中的时钟一直在运行
你是对的,至少他们应该这样做。不过,检查
DispatchTime
是否挂起确实很棘手:当iOS应用程序在Xcode调试会话下运行时,它有无限的后台时间,并且不会被挂起。此外,即使在没有连接Xcode的情况下使用应用程序时,我也无法确认DispatchTime
在任何情况下都被暂停。然而,我发现还有另一个关键属性:DispatchTime
不依赖于系统时钟。DispatchWallTime
的工作原理几乎相同(我也不能确认它是否会暂停),除了它取决于系统时钟。为了看到差异,你可以尝试一个更长的计时器,比如5分钟。之后,转到系统设置并将时间向前设置1小时。如果现在打开应用程序,您会注意到
DispatchWallTime
立即过期,而DispatchTime
一直在等待它的时间到来