When my app is about to be terminated, I receive a notification (UIApplicationWillTerminateNotification) so I can fire off a URLSession to have some data sent to a remote server. I'm trying to do this using UIBackgroundTask, which according the Apple documentation gives me 5 seconds to perform a URLSesstionDataTask. The problem, however, is that my code runs completely fine, except for the fact that the completionHandler of my data task doesn't get executed. It has nothing to do with the 5 seconds expiring, because I tried executing some code AFTER the data task and that code runs fine as well. I also used DispatchQueue to run the completionHandler in the main thread and it didn't work either. Does anyone know first of all if this is possible, and if so, how to do it?
I implemented the same data task in both
… so even if the app gets terminated from the background/suspended state, the required data task will already have been performed the moment my app was moved to the background.-applicationDidEnterBackground
Cool. Most folks who ask me about this want to stay logged in while suspended in the background, which makes things much harder.
So the only problem there's left is that the completionHandler of the actual data task doesn't get executed on app termination.
OK. To fix this you have to block the main thread within
-applicationWillTerminate:
method (or, equivalently, in your
UIApplicationWillTerminateNotification
observer) waiting for the network request to complete. The standard approach for this is to use a dispatch semaphore. For example:
let sem = DispatchSemaphore(value: 0)
startSomethingAsync(completionHandler: {
sem.signal()
})
sem.wait()
IMPORTANT There’s two key things to note here:
You have to make sure that the async work doesn’t rely on any work to be done on the main thread (or queue). If it does, you’ll deadlock, because the main thread is blocked on line 5.
In real code you should wait with a timeout so that you don’t block for too long if the network is not working. Without the timeout, you could block indefinitely, and you’ll eventually be killed by the watchdog (which will generate a crash log, which you don’t need).
Finally, be aware that this doesn’t guarantee that you’ll successfully log out of your server when quitting. For example:
The network could be offline when you terminate (or move to the background)
You might crash, at which point none of this code will run
You’ll have to engineer your server to be resilient in the face of such failures.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"