Fetching Website Data into Memory

Overview

For small interactions with remote servers, you can use the NSURLSessionDataTask class to receive response data into memory (as opposed to using the NSURLSessionDownloadTask class, which stores the data directly to the file system). A data task is ideal for uses like calling a web service endpoint.

You use a URL session instance to create the task. If your needs are fairly simple, you can use the sharedSession instance of the NSURLSession class. If you want to interact with the transfer through delegate callbacks, you’ll need to create a session instead of using the shared instance. You use a NSURLSessionConfiguration instance when creating a session, also passing in a class that implements NSURLSessionDelegate or one of its subprotocols. Sessions can be reused to create multiple tasks, so for each unique configuration you need, create a session and store it as a property.

Note

Be careful to not create more sessions than you need. For example, if you have several parts of your app that need a similarly configured session, create one session and share it among them.

Once you have a session, you create a data task with one of the dataTask() methods. Tasks are created in a suspended state, and can be started by calling resume.

Receive Results with a Completion Handler

The simplest way to fetch data is to create a data task that uses a completion handler. With this arrangement, the task delivers the server’s response, data, and possibly errors to a completion handler block that you provide. Figure 1 shows the relationship between a session and a task, and how results are delivered to the completion handler.

Figure 1

Creating a completion handler to receive results from a task

To create a data task that uses a completion handler, call the dataTaskWithURL: method of URLSession. Your completion handler needs to do three things:

Verify that the error parameter is nil. If not, a transport error has occurred; handle the error and exit.

Check the response parameter to verify that the status code indicates success and that the MIME type is an expected value. If not, handle the server error and exit.

Use the data instance as needed.

Listing 1 shows a startLoad() method for fetching a URL’s contents. It starts by using the NSURLSession class’s shared instance to create a data task that delivers its results to a completion handler. After checking for local and server errors, this handler converts the data to a string, and uses it to populate a WKWebView outlet. Of course, your app might have other uses for fetched data, like parsing it into a data model.

The completion handler is called on a different Grand Central Dispatch queue than the one that created the task. Therefore, any work that uses data or error to update the UI — like updating webView — should be explicitly placed on the main queue, as shown here.

Receive Transfer Details and Results with a Delegate

For a greater level of access to the task’s activity as it proceeds, when creating the data task, you can set a delegate on the session, rather than providing a completion handler. Figure 2 shows this arrangement.

You need to create your own URLSession instance when using the delegate approach, rather than using the URLSession class’s simple shared instance. Creating a new session allows you to set your own class as the session’s delegate, as shown in Listing 2.

URLSession:task:didCompleteWithError: first looks to see if a transport-level error has occurred. If there is no error, it attempts to convert the receivedData buffer to a string and set it as the contents of webView.

The various delegate protocols offer methods beyond those shown in the above code, for handling authentication challenges, following redirects, and other special cases. Using a URL Session, in the URLSession discussion, describes the various callbacks that may occur during a transfer.