3 min read

Downloading JSON Asynchronously in Swift 2

Retrieving data from a RESTful web API is a fundamental task in iOS development. When we perform network operations we want them to be asynchronous — meaning that we want it to be done in the background, while other important tasks are being performed.
Downloading JSON Asynchronously in Swift 2

Retrieving data from a RESTful web API is a fundamental task in iOS development. Making a network request using the NSData class does not allow for concurrency, as it is a synchronous operation. When we perform network operations we want them to be asynchronous, meaning that we want it to be done in the background, while other important tasks are being performed. The NSURLSession class, and associated methods, enables us to do this.

Before we walk through code, let’s solidify the aforementioned concepts with an analogy: Think of iOS as a highway in the United States with multiple lanes, where each lane is a queue. Furthermore, the cars in each lane are analogous to blocks of executable code, i.e. threads. On a highway, the left lane is typically reserved for faster moving traffic. The “left lane” in iOS is called the main queue and it is reserved for user interface tasks, such as when a user taps a button or scrolls on a table view. We never want the main queue to get backed up because then our app would be slow and unresponsive.

A networking call on the main thread can block the user interface tasks if the networking request takes a long time because of a slow connection. This will create a frustrating user experience. All networking code should be done in a background queue, i.e. the middle and right lanes, so we don’t block the user interface. When a networking request is complete, we can move the results from the background queue to the main queue to update the user interface.

In this example, we will download JSON from JSONPlaceholder, which is a convenient web service with test data.

let websiteEndpoint = NSURL(string: “http://jsonplaceholder.typicode.com/posts")

We will also be using SwiftyJSON to make dealing with the JSON response easy, so add it to your project.

Using the NSURLSession class, we can create a task to fetch the data. In order to use NSURLSession, we need to provide it with configuration information. Luckily, Apple has provided a default session configuration object that suits our needs.

let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)

Before using our newly created session, we need to create a request object using NSURLRequest.

let request = NSURLRequest(URL: websiteEndpoint!)

NSURLRequest takes a URL as its initializer and defaults to a GET request. NSURL is an optional type in Swift, so we can either use if-let syntax to check before unwrapping it or use “!” to force unwrap it. In this case, we know that the websiteEndpoint constant has a value, so we can force unwrap it. Now we can use this request to perform an NSURLSessionDataTask.

NSURLSessionDataTask returns the data in memory as an NSData object. This task is created as a method on our session object. When Xcode brings up its autocompletion, select the dataTaskWithRequest with the request and completionHandler parameters.

let dataTask = session.dataTaskWithRequest(request: NSURLRequest, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void)

We will pass in our request object into the request parameter of this method. The completionHandler parameter is a closure. Closures are very useful as callback mechanisms in iOS development because they are a combination of a function and an environment of captured variables. If this doesn’t make sense to you, don’t worry I plan on writing a dedicated post on closures in the near future. For now, just think of it as an anonymous function and follow along with me.

When the last parameter of a function or method is a closure, we can write the write the closure outside of the parenthesis. This is known as trailing closure syntax. In our closure, we need to do three things:

  1. Check the HTTP response code of the GET request
  2. If the response code is 200, get the data
  3. If the response code is something else, handle this error.

To check the HTTP response code, we can downcast the response as an NSHTTPURLResponse and perform our check. The response value in the closure is an optional, so we’ll use if-let syntax to unwrap it. The result looks like this:

let dataTask = session.dataTaskWithRequest(request) {
  (let data, let response, let error) in
    if let httpResponse = response as? NSHTTPURLResponse {
      switch(httpResponse.statusCode) {
      case 200:
        let jsonObject = JSON(data: data!)
        completion(jsonObject)
      default:
        print(“GET request not successful HTTP status code: \(httpResponse.statusCode)”)
      }
    } else {
        print(“Error: Not a valid HTTP response”)
    }
  dataTask.resume()
}

Now that we’ve created a data task and assigned it to a constant, the only thing left is to run our task. In order to do this, we will call dataTask.resume().

Congrats, you’ve now written asynchronous code to download JSON from a web API! Thanks for reading this guide. I plan on writing more topics on iOS development so stay tuned.