Networking in Swift: Building the Swift Client, Part 3

This is part three in the tutorial segment on building a Swift client application to query a RESTful web API, from our series of articles on networking in Swift. In the first segment, we created a custom RESTful API in PHP that serves up the inventory of our hypothetical plumbing supply shop.

In this segment, we have been building a Swift client which queries this API and delivers that inventory content to our end user. In part one, we got our Swift application up and running. In part two of building the Swift client, we created our basic data model, hooked up the segues to our inventory views, and successfully handled raw responses from the server by printing them to the Xcode console.

In the present article, we'll create model objects from the JSON dictionary returned by the server (at the end of part two), and display our inventory item lists in their respective table view controllers.

Model Objects
When we left off in part two, we were filling out the requestInventory method in our PlumbingSupplyInventoryTableViewController. Currently, that method simply prints the returned JSON dictionary to the Xcode console. We'll now create model objects from this dictionary by factoring out the relevant code from the requestInventory method and placing them in a separate method to handle this logic. In your PlumbingSupplyInventoryTableViewController file, add the following method below the requestInventory function that we were working on in the previous article:

Notice that in the last line we do not print out the jsonResult dictionary object but instead wrap it in an array and return it to the caller. In the requestInventory method, replace the three lines of code we factored out into the new inventoryItems method with the following two lines of code:

If you run the app and select one of the two inventory item categories, you should see the same response as before in your console, but wrapped in an array. We'll now refine the raw JSON data. Replace the return [jsonResult] line of code in the inventoryItems method with the following snippet:


Let's take a closer look at this. The first line gets the raw data dictionary object from the JSON results container. The second line defines a container that will hold model objects that are built from the raw data dictionary objects from line one. Inside the for loop we iterate through the raw data dictionary objects and build an array of refined data objects. And in our last line we simply return the array of model objects.

If you now run the app again, you'll see the difference in the Xcode console output, which now returns a tidy array mapping individual inventory items to their memory locations. Let's display these inventory lists in their respective views.

Displaying Our Inventory Item List
Return to the main storyboard. Locate and select one of the table view cells from our PlumbingSupplyInventoryTableViewController scene. In the Attributes Inspector, locate the Style drop down menu and select the option “Basic.” Locate the Identifier field and type in “Cell”. Finally, locate the Accessory drop down menu and select the option “Disclosure Indicator.” Do the same for the other cell as well.

Now open the file PlumbingSupplyInventoryTableViewController.swift file. Inside and toward the top of the class, add the following property:

This data source property will supply our dynamic table view cells with the information to display on screen. The number of items in our data source will always be equal to the number of items from a single plumbing supply inventory category. In the same class  replace the default boilerplate code for the three methods below with the following snippets:

These data source methods are called by the system to query this controller on how to proceed when building our table view and displaying content within it. In the first method we simply tell the system that our table view will display only one section. The second method says that the number of items in our single table view section is equal to the number of items in our data source.

The last method does several things to build a table view cell. In the first line (line 12 in the snippet above) it dequeues a reusable cell. When scrolling a table view, table view cells that scroll off the screen are placed on a queue for reuse and cells that scroll onto the screen are removed from this queue and reused. This process helps speed up table view performance which makes possible the smooth table view scrolling with which we are all familiar. On the second line (line 13) we utilize the indexPath object to get the row number of the cell that is next to become visible in our table view; the row number corresponds to a unique item in our data source. There is a one-to-one correspondence between the cells and the items in our data source. The following line gets the name of an inventory item and assigns it to the label of the next cell to become visible. The last line simply returns that cell.

Let's jump back to where we defined our requestInventory function. In this method, replace this line of code that reads println(inventoryItems) with the following snippet:

What's going on here? In line 1, we capture a reference to the data source that is received from the self.inventoryItems(data) method call. The next segment is a C level API call to a dispatch system, on a queue of our choice, which executes code that we place inside its block/closure. The code inside the closure performs updates to our UI elements.

According to Apple's documentation, any code that updates UI elements must be executed on the main queue—which is what we do. The first line within the closure asks our table view to reload since we have assigned items to its data source. The second line hides the web activity indicator spinner, since our request for web content has terminated. Run the app and select on of the two plumbing supply categories. Once the content downloads you should see a table view similar to the one depicted below:


Success! We've successfully displayed the list of inventory items returned by the web API. Notice, however, that we did not use the callback responseHandler( error: nil, items: nil) closure but instead updated our UI in the method from above. We leave this as an exercise for the reader to implement. If you are not sure how to go about implementing this, don't worry, we wrote another method on a different controller that uses the closure to update its UI elements after an update. We do this towards the end of this tutorial.

This project can be found on GitHub.

We're almost done! In the next article, we'll display thumbnail images alongside each of the items in our inventory list above. And then in the final tutorial, we'll build our item description scene for each item in the inventory that displays the full image along with the extended description supplied by our API.

Index
Introduction
Introduction and Overview: From the Back End API to the End User Application

The Web API
Building a RESTful API in PHP, Part 1
Building a RESTful API in PHP, Part 2

The Swift Client App
Networking in Swift: Building the Swift Client, Part 1
Networking in Swift: Building the Swift Client, Part 2
Networking in Swift: Building the Swift Client, Part 3
Networking in Swift: Building the Swift Client, Part 4
Networking in Swift: Building the Swift Client, Part 5


This tutorial was authored by Stefan Agapie, a Senior iOS Software Engineer, and adapted for the present piece. 

2 comments:

  1. Replace "println(inventoryItems)" with self.dataSource = self.inventoryItems(data)

    dispatch_async(dispatch_get_main_queue()!, { () -> Void in
    self.tableView.reloadData()
    self.webActivityIndicator.hidden = true
    })

    Not "println(response)"


    Wow, this tutorial is buggy.

    ReplyDelete
    Replies
    1. Hey, thanks for catching that typo! The post has been updated.

      Delete