The NSURLSession class and related classes provide an API for downloading content. This API provides a rich set of delegate methods for supporting authentication and gives your app the ability to perform background downloads when your app is not running or, in iOS, while your app is suspended.
Language
- Swift
- Objective-C
SDKs
- iOS 7.0+
- macOS 10.9+
- tvOS 7.0+
- watchOS 2.0+
Overview
The NSURLSession class natively supports the data, file, ftp, http, and https URL schemes, with transparent support for proxy servers and SOCKS gateways, as configured in the user’s system preferences. You can also add support for your own custom networking protocols and URL schemes (for your app’s private use).
Important
The NSURLSession API involves many different classes working together in a fairly complex way that may not be obvious if you read the reference documentation by itself. Before using this API, you should read URL Session Programming Guide to gain a conceptual understanding of how these classes interact with one another.
With the NSURLSession API, your app creates one or more sessions, each of which coordinates a group of related data transfer tasks. For example, if you are writing a web browser, your app might create one session per tab or window, or one session for interactive use and another session for background downloads. Within each session, your app adds a series of tasks, each of which represents a request for a specific URL (following HTTP redirects if necessary).
The tasks within a given URL session share a common session configuration object, which defines connection behavior, such as the maximum number of simultaneous connections to make to a single host, whether to allow connections over a cellular network, and so on. The behavior of a session is determined in part by which method you call when creating its configuration object:
The singleton shared session (which has no configuration object) is for basic requests. It is not as customizable as sessions that you create, but it serves as a good starting point if you have very limited requirements. You access this session by calling the shared() class method. See that method’s discussion for more information about its limitations.
Default sessions behave much like the shared session (unless you customize them further), but let you obtain data incrementally using a delegate. You can create a default session configuration by calling the default() method on the
URLSessionConfigurationclass.Ephemeral sessions are similar to default sessions, but do not write caches, cookies, or credentials to disk. You can create an ephemeral session configuration by calling the ephemeral() method on the
URLSessionConfigurationclass.Background sessions let you perform uploads and downloads of content in the background while your app is not running. You can create a background session configuration by calling the
backgroundSessionConfiguration(_:)method on theURLSessionConfigurationclass.
The session configuration object also contains a reference to URL cache and cookie storage objects that may be used when making requests and handling the responses, depending on the configuration and request type.
The tasks in a session also share a common delegate that lets you provide and obtain information when various events occur—when authentication fails, when data arrives from the server, when data is ready to be cached, and so on. For all background downloads and uploads, you must provide a delegate that conforms to the URLSessionDownloadDelegate Objective-C protocol. Otherwise, if you don’t need any of the features provided by a delegate, you can use this API without providing a delegate by passing nil when you create a session.
Important
The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you do not invalidate the session, your app leaks memory until it exits.
Within a session, you create tasks that optionally upload data to a server, then retrieve data from the server either as a file on disk or as one or more NSData objects in memory. The NSURLSession API provides three types of tasks:
Data tasks send and receive data using
NSDataobjects. Data tasks are intended for short, often interactive requests to a server.Upload tasks are similar to data tasks, but they also send data (often in the form of a file), and support background uploads while the app is not running.
Download tasks retrieve data in the form of a file, and support background downloads and uploads while the app is not running.
Like most networking APIs, the NSURLSession API is highly asynchronous. It returns data to your app in one of two ways, depending on the methods you call:
To a completion handler block that is called when a transfer finishes successfully or with an error.
By calling methods on the session’s delegate as data is received and when the transfer is complete.
In addition to delivering this information to delegates, the NSURLSession API provides status and progress properties that you can query if you need to make programmatic decisions based on the current state of the task (with the caveat that its state can change at any time).
URL sessions also support canceling, restarting or resuming, and suspending tasks, and provide the ability to resume suspended, canceled, or failed downloads where they left off.
URL Session Class Hierarchy
The NSURLSession API consists of the following classes (nested to show subclass relationships):
URLSession—A session object.URLSessionConfiguration—A configuration object used when initializing the session.URLSessionTask—The base class for tasks within a session.URLSessionDataTask—A task for retrieving the contents of a URL as anNSDataobjectURLSessionUploadTask—A task for uploading a file, then retrieving the contents of a URL as anNSDataobject
URLSessionDownloadTask—A task for retrieving the contents of a URL as a temporary file on diskURLSessionStreamTask—A task for establishing a TCP/IP connection
In addition, the NSURLSession API provides four protocols that define delegate methods your app can implement to provide more fine-grained control over session and task behavior.
URLSessionDelegate—Defines delegate methods to handle session-level eventsURLSessionTaskDelegate—Defines delegate methods to handle task-level events common to all task typesURLSessionDataDelegate—Defines delegate methods to handle task-level events specific to data and upload tasksURLSessionDownloadDelegate—Defines delegate methods to handle task-level events specific to download tasksURLSessionStreamDelegate—Defines delegate methods to handle task-level events specific to stream tasks
Finally, the NSURLSession API uses a number of classes that are also commonly used with other APIs such as NSURLConnection and NSURLDownload. Some of these shared classes include:
NSURL—An object that contains a URL.NSURLRequest—Encapsulates metadata related to a URL request, including the URL, request method, and so on.URLResponse—Encapsulates metadata related to a server’s response to a request, such as the content MIME type and length.HTTPURLResponse—Adds additional metadata specific to HTTP requests, such as response headers.
CachedURLResponse—Encapsulates anURLResponseobject, along with the actual body data of the server’s response, for caching purposes.
Authentication and TLS Customization
When a server requests authentication or provides credentials during TLS negotiation, the URL session calls methods on its delegate, allowing you to handle the authentication or certificate validation in a custom manner. The method it calls depends on whether you are handling a task-specific challenge or a session-wide challenge. Table 1 shows the difference between the two.
Session-level and connection-level challenges
For task-specific challenges, the session calls its delegate’s urlSession(_:task:didReceive:completionHandler:) method.
For session-wide authentication challenges, the session calls its delegate’s urlSession(_:didReceive:completionHandler:) method if that method exists. Otherwise, it calls the delegate’s urlSession(_:task:didReceive:completionHandler:) method.
If you do not implement these methods, when a request requires client authentication, the URL session attempts to authenticate as follows:
Using the authentication information provided as part of the requested URL, if available
By looking up Internet passwords and certificates in the user’s keychain (in macOS) or the app’s keychain (in iOS)
Then, if credentials are not available, or if the server rejects the credentials, the connection continues without authenticating. For HTTP and HTTPS requests, the connection attempt fails with an appropriate HTTP status code, and may provide alternative content (such as the public version of a private site). For other URL types (such as FTP),the connection fails with a connection failure.
Note
Kerberos authentication is handled transparently. The delegate methods described here do not apply to Kerberos authentication.
App Transport Security (ATS)
Starting in iOS 9.0 and OS X v10.11, a new security feature called App Transport Security (ATS) is enabled by default for all HTTP connections made with NSURLSession. ATS requires that HTTP connections use HTTPS (RFC 2818).
For more information, see NSAppTransportSecurity in the Information Property List Key Reference.
Using an URL Session
To make a request using the NSURLSession class:
Create a session configuration. For background sessions, this configuration must contain a unique identifier. Store that identifier, and use it to reassociate with the session if your app crashes or is terminated or suspended.
Create a session, specifying a configuration object and, optionally, a delegate.
Create task objects within a session that each represent a resource request. These task objects are subclasses of
URLSessionTask—URLSessionDataTask,URLSessionUploadTask, orURLSessionDownloadTask, depending on the behavior you are trying to achieve.Each task starts out in a suspended state. After your app calls
resume()on the task, it begins downloading the specified resource.
After you start a task, the session calls methods on its delegate, as follows:
If the initial handshake with the server requires a connection-level challenge (such as an SSL client certificate),
NSURLSessioncalls either theurlSession(_:task:didReceive:completionHandler:)orurlSession(_:didReceive:completionHandler:)delegate method, as previously described in Authentication and TLS Customization.For more information about writing an authentication delegate method for
NSURLSession, read URL Session Programming Guide.If the task’s data is provided from a stream, the
NSURLSessionobject calls the delegate’surlSession(_:task:needNewBodyStream:)delegate method to obtain anNSInputStreamobject that provides the body data for the new request.During the initial upload of body content to the server (if applicable), the delegate periodically receives
urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)callbacks that report the progress of the upload.The server sends a response.
If the response indicates that authentication is required, the session calls its delegate’s
urlSession(_:task:didReceive:completionHandler:)method. Go back to step 2.If the response is an HTTP redirect response, the
NSURLSessionobject calls the delegate’surlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)method. That delegate method calls the provided completion handler with either the providedNSURLRequestobject (to follow the redirect), a newNSURLRequestobject (to redirect to a different URL), ornil(to treat the redirect’s response body as a valid response and return it as the result).If you decide to follow the redirect, go back to step 2.
If the delegate doesn’t implement this method, the redirect is followed up to the maximum number of redirects.
For a (re-)download task created by calling
downloadTask(withResumeData:)ordownloadTask(withResumeData:completionHandler:),NSURLSessioncalls the delegate’surlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)method with the new task object.For a data task, the
NSURLSessionobject calls the delegate’surlSession(_:dataTask:didReceive:completionHandler:)method. Decide whether to convert the data task into a download task, and then call the completion callback to continue receiving data or downloading data.If your app chooses to convert the data task to a download task,
NSURLSessioncalls the delegate’surlSession(_:dataTask:didBecome:)method with the new download task as a parameter. After this call, the delegate receives no further callbacks from the data task, and begins receiving callbacks from the download task.During the transfer from the server, the delegate periodically receives a task-level callback to report the progress of the transfer.
For a data task, the session calls the delegate’s
urlSession(_:dataTask:didReceive:)method with the actual pieces of data as they are received.For a download task, the session calls the delegate’s
urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)method with the number of bytes successfully written to disk. If the user tells your app to pause the download, cancel the task by calling thecancel(byProducingResumeData:)method.Later, if the user asks your app to resume the download, pass the returned resume data to either the
downloadTask(withResumeData:)ordownloadTask(withResumeData:completionHandler:)method to create a new download task that continues the download. (Go to step 1.)For a data task, the
NSURLSessionobject may call the delegate’surlSession(_:dataTask:willCacheResponse:completionHandler:)method. Your app should then decide whether to allow caching. If you do not implement this method, the default behavior is to use the caching policy specified in the session’s configuration object.If the response is multipart encoded, the session may call the delegate’s
didReceiveResponsemethod again, followed by zero or more additionaldidReceiveDatacalls. If this happens, go to step 8 (handling thedidReceiveResponsecall).If a download task completes successfully, then the
NSURLSessionobject calls the task’surlSession(_:downloadTask:didFinishDownloadingTo:)method with the location of a temporary file. Your app must either read the response data from this file or move it to a permanent location before this delegate method returns.When any task completes, the
NSURLSessionobject calls the delegate’surlSession(_:task:didCompleteWithError:)method with either an error object ornil(if the task completed successfully).If the download task can be resumed, the
NSErrorobject’suserInfodictionary contains a value for theNSURLSessionDownloadTaskResumeDatakey. Your app should pass this value to calldownloadTask(withResumeData:)ordownloadTask(withResumeData:completionHandler:)to create a new download task that continues the existing download.If the task cannot be resumed, your app should create a new download task and restart the transaction from the beginning.
In either case, if the transfer failed for any reason other than a server error, go to step 3 (creating and resuming task objects).
Note
NSURLSessiondoes not report server errors through the error parameter. The only errors your delegate receives through the error parameter are client-side errors, such as being unable to resolve the hostname or connect to the host. The error codes are described in URL Loading System Error Codes.Server-side errors are reported through the HTTP status code in the
NSHTTPURLResponseobject. For more information, read the documentation for theHTTPURLResponseandURLResponseclasses.If you no longer need a session, you can invalidate it by calling either
invalidateAndCancel()(to cancel outstanding tasks) orfinishTasksAndInvalidate()(to allow outstanding tasks to finish before invalidating the object). If you don’t invalidate the session, it automatically goes away when your app is terminated (unless it’s a background session with active tasks).After invalidating the session, when all outstanding tasks have been canceled or have finished, the session calls the delegate's
urlSession(_:didBecomeInvalidWithError:)method. When that delegate method returns, the session disposes of its strong reference to the delegate.
If your app cancels an in-progress download, the NSURLSession object calls the delegate’s urlSession(_:task:didCompleteWithError:) method as though an error occurred.
Background Transfer Considerations
Because restarting your app (or waiting for the user to relaunch it) is relatively expensive, some features are unavailable in background sessions. As a result:
The session must provide a delegate for event delivery. Because your app might quit and be relaunched while the transfer is in progress, completion handler blocks are not supported. (For uploads and downloads, these delegates behave the same as for in-process transfers.)
Only HTTP and HTTPS protocols are supported. Other built-in networking protocols are not supported, and neither are custom networking protocols.
Only upload and download tasks are supported (no data tasks).
Redirects are always followed.
The number of system-wide concurrent background transfers is limited.
A background task may be cancelled if it fails to meet a system-specified throughput limit. That is to say, if a long-running task is not sending or receiving enough data over a period of time, it may be cancelled to be resumed later. Therefore, it is important to make a transfer resumable, if possible.
If the background transfer is initiated while the app is in the background, the task is treated as discretionary. In other words, it behaves like a task in a session whose configuration object’s
isDiscretionaryproperty istrue.
If these limitations are incompatible with your app’s needs, you can also download remote resources to a file in non-background sessions. If you do, then when the user puts your iOS app into the background or quits your macOS app, pause any active downloads by calling the cancel(byProducingResumeData:) method. Resume the downloads when the user brings your app to the foreground again. If your app is terminated before you have obtained resume data, you’ll be unable to resume the download.
Note
Background sessions are optimized for transferring a small number of large resources that can be resumed as necessary. If possible, you may want to investigate methods of optimizing server-side behavior to facilitate this kind of usage, such as:
Making requests to endpoints that send or receive zip or tar archives instead of making several individual calls.
Making requests to endpoints that send or receive incremental diffs for replication between the client and server.
Making requests to endpoints that return an upload identifier, which can then be used to track and resume the transfer of data to the server.
Adding an intermediary web service that proxies requests to a canonical web service in order to facilitate any of the aforementioned optimizations.
NSCopying Behavior
Session and task objects conform to the NSCopying protocol as follows:
When your app copies a session or task object, you get the same object back.
When your app copies a configuration object, you get a new copy that you can independently modify.
Thread Safety
The URL session API itself is fully thread-safe. You can freely create sessions and tasks in any thread context, and when your delegate methods call the provided completion handlers, the work is automatically scheduled on the correct delegate queue.
Warning
Your urlSessionDidFinishEvents(forBackgroundURLSession:) session delegate method may be called on a secondary thread. However, in iOS, your implementation of that method may need to call a completion handler provided to you in your application(_:handleEventsForBackgroundURLSession:completionHandler:) app delegate method. You must call that completion handler on the main thread.