Create tasks that download files while your app is inactive.
For long-running and nonurgent transfers, you can create tasks that run in the background. These tasks continue to run even when your app is suspended, allowing your app to access the downloaded file when the app is resumed.
Configure the Background Session
Create a background
NSURLSessionobject with the class method
Session Configuration With Identifier:
NSURLSession, providing a session identifier that is unique within your app. Because most apps need only a few background sessions (usually one), you can use a fixed string for the identifier, rather than a dynamically generated identifier. The identifier doesn’t need to be unique globally.
To have the system to wake up your app when a task completes and the app is in the background, make sure the
sessionproperty is set to
Sends Launch Events
For time-insensitive tasks, enable the
discretionaryproperty, so the system can wait for optimal conditions to perform the transfer, such as when the device is plugged in or connected to Wi-Fi.
NSURLSessioninstance to create a
NSURLSessioninstance. Provide a delegate, to receive events from the background transfer.
Create and Schedule the Download Task
You create download tasks from the session with either the
download method that takes a URL, or the
download method that takes a
URLRequest instance. You set properties on this method to help the system optimize its behavior.
As shown in Listing 2, create a download task with
Task With URL:
Optionally, set the
earliestproperty to schedule the download to begin at a particular point in the future. The download isn’t guaranteed to begin at precisely this time, but it won’t start sooner.
To help the system schedule network activity efficiently, set the properties
Of Bytes Client Expects To Send
count. These values are best-guess upper bounds on the expected byte count, and should account for headers as well as body data.
Of Bytes Client Expects To Receive
To start the task, call
In Listing 2, the task is set to begin at least one hour in the future and is configured to send around 200 bytes of data and receive around 500 KB.
Handle App Suspension
Different app states affect how your app interacts with the background download. In iOS, your app could be in the foreground, suspended, or even terminated by the system. See Managing Your App's Life Cycle for more information about these states.
If your app is in the background, the system may suspend your app while the download is performed in another process. In this case, when the download finishes, the system resumes the app and calls the
application:. This method receives the session identifier you created in Listing 1 as its second parameter.
This delegate method also receives a completion handler as its final parameter. Immediately store this handler wherever it makes sense for your app, perhaps as a property of your app delegate, or of your class that implements
NSURLSession. In Listing 3, this completion handler is stored in an app delegate property called
When all events have been delivered, the system calls the
URLSession method of
NSURLSession. At this point, fetch the
background stored by the app delegate in Listing 3 and execute it. Listing 4 shows this process.
Note that because
URLSession may be called on a secondary queue, it needs to explicitly execute the handler (which was received from a UIKit method) on the main queue.
Access the File, or Move It to a Permanent Location
Once your resumed app calls the completion handler, the download task finishes its work and calls the delegate’s
URLSession: method. At this point, the file is fully downloaded, and will be available until your delegate method returns. If you only need to read it once, you can access the file immediately in its temporary location. If you want to preserve the file, move it to a permanent location like the
Documents directory, as described in Downloading Files from Websites.
Recreate the Session If the App Was Terminated
If the system terminated the app while it was suspended, the system relaunches the app in the background. As part of your launch time setup, recreate the background session (see Listing 1), using the same session identifier as before, to allow the system to reassociate the background download task with your session. You do this so your background session is ready to go whether the app was launched by the user or by the system. Once the app relaunches, the series of events is the same as if the app had been suspended and resumed, as discussed earlier in Handle App Suspension.
Comply with Background Transfer Limitations
With background sessions, the actual transfer is performed by a process that is separate from your app’s process. Because restarting your app’s process is fairly expensive, a few features are unavailable, resulting in the following limitations:
The session must provide a delegate for event delivery. (For uploads and downloads, the delegates behave the same as for in-process transfers.)
Only HTTP and HTTPS protocols are supported (no custom protocols).
Redirects are always followed. As a result, even if you have implemented
URLSession:, it is not called.
task: will Perform HTTPRedirection: new Request: completion Handler:
Only upload tasks from a file are supported (uploads from data instances or a stream fail after the app exits).
Use Background Sessions Efficiently
When the system resumes or relaunches your app, it uses a rate limiter to prevent abuse of background downloads. When your app starts a new download task while in the background, the task doesn't begin until the delay expires. The delay increases each time the system resumes or relaunches your app.
As a result, if your app starts a single background download, gets resumed when the download completes, and then starts a new download, it will greatly increase the delay. Instead, use a small number of background sessions — ideally just one — and use these sessions to start many download tasks at once. This allows the system to perform multiple downloads at once, and resume your app when they have completed.
Keep in mind, though, that each task has its own overhead. If you find you need to launch thousands of download tasks, change your design to perform fewer, larger transfers.