In parts 1 & 2 to this Developing iOS8 Apps Using Swift tutorial series we went over some basics of Swift, and set up a simple example project that creates a Table View and a puts some API results from iTunes Search API inside of them. If you haven’t read that yet, check out Part 1 and Part 2.

In this section we’re going to take a stop and clean up some of the code we’ve created so far by removing our network logic from our view controller code, and fixing some other issues that will hurt our performance. This may not be the most glamorous part of writing a new app, but it’s important! Let’s do it…

Split up your iOS8 Swift Code

First things first, let’s rename our View Controller to be something more meaningful. Open up your ViewController.swift file and replace all references to ‘ViewController’ with our new name, ‘SearchResultsViewController’. Rename the file as well to SearchResultsViewController.swift.

If you try to run the app from here you’ll get a crash. This is because our storyboard file hasn’t been updated to know about the new class! So open up the Main.storyboard, select your ‘View Controller’ object in the scene (the left-hand side nav), and then select the Identity Inspector (right-hand side, third button.)

From here let’s change the class from ‘ViewController’ to ‘SearchResultsViewController’. Now we should be back on track. Check that the project still works, and let’s proceed.

Let’s now move the API code out to it’s own class. Right click in the xcode navigation pane and select ‘New File…’. This one is going to be a Cocoa Touch Class, under the iOS->Source navigation option.

This one handles all API work, so I’m going to call it APIController.

Now let’s grab our searchItunesFor() function, and all our delegate functions like connection(didRecieveResponse….). Cut and paste these out of the Search controller and in to the APIController. You’ll also need to copy over the data variable for the response to build it’s results.

If you try to build this straight away you’ll see three errors:

1) searchItunesFor() is now undefined in our SearchResultsViewController.
2) self.tableData is now undefined in the APIController.
3) self.appsTableView is now undefined in the APIController.

To deal with this we need to let these objects know about each other. So let’s make APIController a child object of our SearchResultsViewController. It’s pretty easy to do, just add the following line underneath your SearchResultsViewController class definition:


1
var api: APIController = APIController()

Now modify the line that calls searchItunesFor() to this:


1
api.searchItunesFor("Angry Birds")

The only difference here is that we’re calling the method from an instance of an APIController, as opposed to doing this all procedural.

That takes care of the first set of errors, but now we need to also get APIController’s results back to the SearchResultsViewController. We would like for our API controller to be able to respond to arbitrary API calls, so we should define a protocol that views can subscribe to in order to get results!

Defining an API protocol

There are two error lines in our APIController right now referencing the tableData results, let’s just remove these. We’re going to use something a little cleaner.

Above the class definition in our APIController, let’s add a protocol that declare the function didRecieveAPIResults() as a required implementation.


1
2
3
protocol APIControllerProtocol {
   func didRecieveAPIResults(results: NSDictionary)
}

This doesn’t do anything on it’s own, but now we can add the protocol to our SearchResultsViewController. Not adhering to the protocol will now cause an error, so we don’t make the silly mistake of not implementing didRecieveAPIResults!

Adhering to the protocol

Now modify your SearchResultsViewController to adhere to the protocol:


1
class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol {

Building now should give an error that SearchResultsViewController doesn’t conform to the APIControllerProtocol, great! Now we just need to add the function within our SearchResultsViewController class. It will look pretty much like the contents of our connectionDidFinishLoading class from before.


1
2
3
4
5
6
7
func didRecieveAPIResults(results: NSDictionary) {
   // Store the results in our table data array
   if results.count>0 {
      self.tableData = results["results"] as NSArray
      self.appsTableView.reloadData()
   }
}

The one thing left to do is change our API Controller to include a delegate object, and to call this method when the connection finished loading some API data.

Using the Protocol

Back in our APIController.swift file, let’s add the delegate, just under the class definition.


1
var delegate: APIControllerProtocol?

The question mark at the end here indicates that delegate is an *optional* value. Without the question mark, we will get a compiler error for not using an initial value for this variable, but with it we’re okay. The delegate object can be of any class here, as long as it adheres to the APIControllerProtocol by defining the method didRecieveAPIResults(), as we have done in our SearchResultsViewController

Finally, in the connectionDidFinishLoading method, let’s remove the tableView code and replace it with our fancy new protocol method:


1
2
3
4
5
6
7
8
9
func connectionDidFinishLoading(connection: NSURLConnection!) {
   // Request complete, self.data should now hold the resulting info
   // Convert the retrieved data in to an object through JSON deserialization
   var err: NSError
   var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

   // Now send the JSON result to our delegate object
   delegate?.didRecieveAPIResults(jsonResult)
}
Download Full Code

Okay, I know that might have seemed like a lot of boilerplate, and now our app does the exact same thing as it did before, but now we have something much more flexible. We can now use APIController for any API call to the iTunes search API, and have a custom delegate get the response. I think we ran out of time on this one, so we’ll move on to the interaction in Part 4

Enjoyed this post?

Subscribe to our RSS Feed or Follow us on twitter to keep up to date with the latest from iOS-Blog. Remember, Sharing is caring so please click one of the following options:

Tags: , ,