Simplifying iOS background tasks

Brad Mueller
2 min readMar 20, 2017

--

On iOS, leaving an app or locking the device triggers your app to go from the Active state, to Background, and promptly, Suspended. The suspended state suspends any code execution and frees up resources for other apps, which is a good thing.

Often, though, we need a little more time for our app to clean up. This is where Background Tasks come into play. Using Background Tasks, iOS will give your app a couple minutes to keep working, before it becomes Suspended.

Imagine your app allows people to take photos and send them to friends. Users might snap a photo, select a recipient, hit send & immediately leave your app. Without a Background Task, that photo may never make it.

Adding background tasks should be easy, but in fact, it’s ugly and cumbersome.

Here is what a normal background task setup looks like:

// Create the background task
__block UIBackgroundTaskIdentifier bgTask;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithName:nil expirationHandler:^{ // End the task so the OS doesn’t kill the app
if (bgTask != UIBackgroundTaskInvalid) {
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
}}];
/* ... Code permitted to execute in background … */// End the task
if (bgTask != UIBackgroundTaskInvalid) {
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}

It’s a lot to swallow. That’s why I made a category on UIApplication to make it simple.

Here is the same functionality using CFABackgroundTask:

CFABackgroundTask *task = [UIApplication cfa_backgroundTask];/* … Code permitted to execute in background … */[task invalidate];

Optionally, if you need to execute some code upon the task’s expiration, you can provide an expiration block via cfa_backgroundTaskWithExpiration:.

Test it out

Here’s a simple example to try. In your AppDelegate.m implement the following in applicationDidEnterBackground::

// Start the background task
CFABackgroundTask *task = [UIApplication cfa_backgroundTask];
// Wait 5 seconds…
dispatch_time_t delayTimer = dispatch_time(DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC);
dispatch_after(delayTimer, dispatch_get_main_queue(), ^(void){
NSLog(@”Application state: %ld”, [[UIApplication sharedApplication] applicationState]);
NSLog(@”Background Time Remaining: %0.1f”, [[UIApplication sharedApplication] backgroundTimeRemaining]);
// End the task
[task invalidate];
});

With the CFABackgroundTask, you’ll see the logs print 5s after entering background. When run without it, those logs aren’t printed — not until you open the app back up.
(NOTE: Be sure to run on a device — the simulator doesn’t always suspend apps like a real device does)

I like to use background tasks often, and I especially like to optimize my development. Whether scheduling local notifications, resizing images, or saving data, CFABackgroundTask is a simple and useful way to make sure your app finishes the job as the user expects.

--

--

Brad Mueller

Co-founder & lead mobile dev at a brilliant little place called @Cellaflora