Background fetching using NSURLSession

Most mobile apps aren’t open very often and tend to stay in the foreground for short time. If the app frequently updates its content from remote sources or if it occasionally performs large data transfers (like downloading audio or video files), since iOS 7 it’s possible to run this kind of tasks while the app is in the background. Thus, when the user opens the app, the latest content is immediately available without requiring any time-consuming updating action.

Background fetches were introduced in iOS 7, allowing developers to improve the user experience by providing content updates even when the app is closed.

This article is the logical continuation of the previous week’s blog post on NSURLSession basics. If you’re not familiar with the session configuration settings and the different types of data transfer tasks, I strongly recommend to take a look at that article before further reading about background fetches.

Enable background fetches

Background fetching must be enable in Xcode before using it in your app. In the project Capabilities tab, switch on the Background Modes feature and select the Background fetch option:

background fetching option in xcode

Data polling occurs when the app is in the background, suspended or not running state. If it is suspended, the system wakes it in order to run the background tasks. If it’s not running, the app is launched in the background. The activation process is similar to manually launching the app by the user, the same AppDelegate methods being invoked. It’s also possible and even recommended to refresh the UI in the background in order to reflect the content updates.

The background fetches are triggered in two different ways:

  • the system automatically launches a fetching operation periodically according to a time interval set by the application and other circumstances related to the app usage and device state (network availability, band width, battery load). We’ll use this type of trigger in the demo app referenced below
  • the app receives a remote notification and launches a background fetch. For example, a push notification can be sent when new content is available for download.

I built upon the demo app used for the previous blog post and implemented the background fetch feature to update the content while the app is closed. The project is available for download on GitHub.

Implement the app delegate methods

The recurring fetches are enabled by setting the minimum background fetching interval for the application, which by default is UIApplicationBackgroundFetchIntervalNever. The value is a NSTimeInterval and we can either use the UIApplicationBackgroundFetchIntervalMinimum constant or set a custom frequency. In either case, the setting is purely informative, because only the system decides the real fetches frequency. Usually, this parameter is set in the app delegate method -application: didFinishLaunchingWithOptions: by invoking -setMinimumBackgroundFetchInterval on the application instance.

When the background fetch is trigger, the app delegate method -application: performFetchWithCompletionHandler: is automatically called. In this method we should implement the data polling, model and UI updating, and, inevitably, finish by calling the completionHandler argument using a UIBackgroundFetchResult constant (UIBackgroundFetchResultNewData, UIBackgroundFetchResultNoData or UIBackgroundFetchResultFailed). The whole process should not take more than 30 seconds, otherwise the system may space out future background fetches.

Because the sample app displays the data downloaded from remote sources in a table view controller, I gave it the responsibility of performing the data polling. When the background fetch is triggered, the application fires a notification observed by the table view controller, which uses the transfer manager to request the remote data:

Perform server polling using background tasks

The remote data is fetched using NSURLSession. Background fetches require a special type of NSURLSessionConfiguration object which is created by calling the class method -backgroundSessionConfigurationWithIdentifier.

Unlike standard session tasks, background download tasks don’t accept blocks to be executed asynchronously after receiving the response, so we have to use the NSURLSession delegate methods to be able to take action when the data transfer is finished. As for content updates triggered from the app (see the previous blog post for more information about that), background fetches use and update a custom cache, then call the completionBlock to update the table view with the new data.

Test background fetches

The easiest way to trigger a background fetch while developing the app is to use the Simulate Background Fetch command from the Debug menu in Xcode. It closes the app if it runs in the foreground and calls the app delegate method -application: performFetchWithCompletionHandler:, allowing to test the background fetching behavior.

Conclusion

I probably presented here the most basic use case for background fetching. Real world apps that need this kind of feature would use the principles I described here, but would also probably contain more code to handle edge cases like interrupted fetches, request errors, etc, making use of the many NSURLSession delegate methods. For more information, I suggest reading the Apple documentation and dive deeper into NSURLSession class family.

 

Catalin Rosioru