Search code examples
iosgrand-central-dispatch

What does DispatchWallTime do on iOS?


I thought the difference between DispatchTime and DispatchWallTime had to do with whether the app was suspended or the device screen was locked or something: DispatchTime should pause, whereas DispatchWallTime should keep going because clocks in the real world keep going.

So I wrote a little test app:

@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())
    }
}

I ran the app on my device. I backgrounded the app, waited for a while, then brought the app to the foreground. Sometimes "waited for a while" included switching off the screen. I got results like this:

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

The delay before the deadline timer fires is not as long as I expected: it's 6 seconds over the 60 second deadline, even though I "slept" the app for considerably longer than that. But even more surprising, both timers fire at the same instant.

So what does wallDeadline do on iOS that's different from what deadline does?


Solution

  • This question has been here for quite a while without any answers, so I'd like to give it a try and point out subtle difference I noticed in practice.

    DispatchTime should pause, whereas DispatchWallTime should keep going because clocks in the real world keep going

    You are correct here, at least they are supposed to work this way. It's really tricky to check that DispatchTime suspends, though: when an iOS app is running under Xcode debugging session, it has unlimited background time and isn't getting suspended. Moreover, even when playing around with the app without Xcode connected, I could not confirm that DispatchTime is paused under whatever conditions. I found, however, that there is another key property: DispatchTime doesn't depend on the system clock. DispatchWallTime works pretty much the same (and I couldn't confirm that it gets paused either), with exception to that it depends on the system clock.

    In order to see the difference, you can try out a little longer timer, say, 5 minutes. After that go to the system settings and set the time 1 hour forward. If you now open the application you can notice, that DispatchWallTime immediately expires whereas DispatchTime keeps waiting for its time to come