我想知道DispatchQueue.asyncAfter(deadline:execute:)
在背景情况下的表现。我试图在documentation中找到更多信息,但是那里什么也没有。
假设我在其中调用:
DispatchQueue.main.asyncAfter(deadline: .now() + 60.0) { ... }
对我而言,最有趣的部分是知道倒计时60秒的计时器何时停止和恢复。
寻找DispatchQueue.asyncAfter(deadline:execute:)
和DispatchQueue.asyncAfter(wallDeadline:execute:)
之间的差异,我从Apple Staff(source)找到了该信息,该信息实际上回答了以下问题:
顺便问一下,您知道为什么Swift Dispatch库中提供了这两种Distict类型吗?
这些模型模拟墙时间(由gettimeofday返回)和马赫绝对时间(由mach_absolute_time返回)之间的差。后者与系统时钟变化无关,但是在您睡眠时停止。在C API中,所有内容都会展平到绝对马赫时间,这意味着您丢失了关键信息。考虑一下,如果您将计时器安排在将来的1秒钟,然后系统休眠2秒钟,将会发生什么情况。
为了清楚起见,DispatchQueue.asyncAfter(deadline:execute:)
使用绝对时间,DispatchQueue.asyncAfter(wallDeadline:execute:)
使用gettimeofday
(墙上时间)。
基于此,我准备了测试以确认这一点:
override func viewDidLoad() {
super.viewDidLoad()
self.textView.text.append(
"expected times: \n1. \(Date().addingTimeInterval(60.0 * 2))\n" +
"2. \(Date().addingTimeInterval(60.0 * 3))\n" +
"3. \(Date().addingTimeInterval(60.0 * 5))\n\n")
DispatchQueue.main.asyncAfter(deadline: .now() + 60.0 * 2) {
self.textView.text.append("\n\(Date()) fired based on ABSOLUTE time (1)!")
}
DispatchQueue.main.asyncAfter(deadline: .now() + 60.0 * 3) {
self.textView.text.append("\n\(Date()) fired based on ABSOLUTE time (2)")
}
DispatchQueue.main.asyncAfter(deadline: .now() + 60.0 * 5) {
self.textView.text.append("\n\(Date()) fired based on ABSOLUTE time (3)!")
}
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 60.0 * 2) {
self.textView.text.append("\n\(Date()) fired based on WALL time (1)!")
}
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 60.0 * 3) {
self.textView.text.append("\n\(Date()) fired based on WALL time (2)")
}
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 60.0 * 5) {
self.textView.text.append("\n\(Date()) fired based on WALL time (3)!")
}
}
我在带有独立调试器的真实设备上运行它并锁定了手机。在恢复应用程序3.5分钟后,有:
根据WALL时间触发(1)!
根据WALL时间(2)触发!
这两个事件正是在我还原应用程序时触发的。这证明了上面的说法。基于绝对时间的事件随后出现,这表明它们的计时器已停止。
答案 0 :(得分:2)
简而言之,当应用暂停后(当用户转到另一个应用时),所有执行都会停止,除非您将其配置为后台执行,否则该计时器不会触发。参见App programming Guide for iOS: Background Execution。
此外,请警惕从Xcode进行测试,因为附加到调试器可能会更改应用程序的生命周期。
答案 1 :(得分:2)
在前台启动的计时器将在后台运行,如果该应用已出于其他原因在后台运行(例如,它正在播放音乐,并且已打开音频的后台模式,或者它正在执行后台“核心定位”,并且已打开“核心定位”的背景模式)。
否则,它将在后台暂停。
答案 2 :(得分:0)
这取决于您的应用程序如何配置后台模式。例如,如果您启用了后台模式,并且设置位置监视器始终保持打开状态,那么即使用户未关闭应用程序,也可以永远在后台运行。因此,在这种情况下,将调用DispatchQueue.asyncAfter回调。
另一方面,如果禁用了后台模式,则应用程序在进入后台时将进入冻结状态,因此不会调用您的回调。在我的测试中,我注意到以下流程:调度队列不会停止,因此,如果您在60秒内调度调度,并且在后台停留100秒钟,那么当回到前台时,将立即调用回调。如果您仅在后台停留30秒钟,那么当您回来时,您将不得不再等待30秒钟。
请注意,如果使用后台任务,您仍然可以禁用后台模式,并保持应用程序在后台运行3分钟。
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// called when the app is about to enter in freez state
[[UIApplication sharedApplication] endBackgroundTask:weakSelf.backgroundTask];
}];