One of the greatest difficulties a developer faces is how to keep code clean while at the same time producing functional code at a steady pace. This is compounded when trying to figure out how to do this AND at the same time learn a new language, such as Apple's Objective-C replacement, Swift.

A little planning in the beginning can help shape the code you build down the road. Failure to do so may result in many hours either spent chasing hard-to-find bugs or in refactoring. This blog is an effort to build a reliable REST client that can be used throughout an app. This also means creating a modular and linear flow to the method calls. This makes it easier for any bugs to be caught.

To begin, create a sample project, selecting the options for a one page app and using the Swift language. This will create a view controller and storyboard for you.

Using .plist

Hard-coded urls, we've all done it. Since this is a best practices blog let's start by looking at adding data to configuration files. Create a new property list file named Config. This will serve as our app's configuration file. Notice it's a .plist file, similar to the ever-present Info.plist. We could add our config elements to the Info file but it's better to leave that as the default for the iOS application and make our own.

To get this data we will need to create our Api class. Create a general Swift file named Api. Add the following to the top of the file:

    var dict = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("Config", ofType: "plist")!)

In the snippet, we construct an NSDictionary object. Why not a regular Dictionary Swift object? Simply put, all of the functionality and libraries currently used by NSString have not been passed to the Swift Dictionary object yet, and is one of the pain points in transferring your app to Swift. If coming from Objective-C, NSString is a known value. Similar to Java's autoboxing, these items can be directly cast to their non-NS counterparts.

    var prodConfigs = dict!["AppConfig_prod"] as NSDictionary
    var someUrl = prodConfigs["base_url"] as NSString

Async Rest Calls

Asynchronous REST calls are a cornerstone of any good REST client. While we could do this synchronously, it is never good to make your UI thread wait on what could be a very unreliable network.

    func makeHTTPGetRequest(url: NSString, callback: APICallback){
        
        var urlObject = NSURL(string: url)
        var request = NSMutableURLRequest(URL: urlObject!)
        request = self.buildRequestHeaders(request)
        request.HTTPMethod = "GET"
        
        htttpRequest(request){
            (data, error) -> Void in
            callback(data, error)
        }
    }
    func htttpRequest(request: NSURLRequest!) {
        var session = NSURLSession.sharedSession()
        var task = session.dataTaskWithRequest(request){ (data, response, error) -> Void in
                println(error)
                println(data)
        }
        task.resume()
    }
    func buildRequestHeaders(request: NSMutableURLRequest) -> NSMutableURLRequest{
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")
        return request
    }

Above we can see the basic calls that will return some data from our REST call. After setting the headers, we use dataTaskWithRequest() to asynchronously retrieve our data, in this case taking the form of an NSData object. To change this to an NSDictionary we simply:

    let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
    var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, 
        options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

We now have a dictionary we can parse until our heart is content, but there's a major problem. None of this data is bubbling up into other methods, much less into the ViewController. Enter callbacks.

Delegates

Callbacks in Swift take the form of delegates. Below I show both a generic callback and a delegate. Delegates in Swift are fairly ubiquitous, and bring some much needed functional style into the language. Begin by adding a new protocol before the class declarations.

    protocol APIControllerProtocol {
        func didReceiveAPIResults(results: NSDictionary?)
    }

Then declare the delegate inside the class, noticing the typealias which makes the code more readable and saves us having to type the callback repeatedly.

    var delegate: APIControllerProtocol?
    init(delegate: APIControllerProtocol?) {
        self.delegate = delegate
    }
    typealias APICallback = ((NSDictionary?, NSString?) -> ())

We can now pass APICallback around as a callback by adding to the method body:

    (data, error) -> Void in

Finished HTTP Request call:

    func htttpRequest(request: NSURLRequest!, callback: APICallback) {
        var session = NSURLSession.sharedSession()
        var task = session.dataTaskWithRequest(request){
            (data, response, error) -> Void in
            if error != nil {
                callback(nil, error.localizedDescription)
            } else {
                let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
                println("responseString = \(responseString!)")
                var jsonResult: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, 
                    options:    NSJSONReadingOptions.MutableContainers, error: nil)
                if let nsDictionaryObject = jsonResult as? NSDictionary {
                    if (jsonResult != nil) {
                        callback(nsDictionaryObject, nil)
                    }else{
                        callback(nil, nil)
                    }
                }
            }
        }
        task.resume()
    }

All that is left to do is to update ViewController to use the delegate. Be sure to add the APIControlProtocol to the class definition along side UIViewController.

lazy var api: API = API(delegate: self)
    func didReceiveAPIResults(results: NSDictionary?) {
        var resultDict = results!
        var someData = resultDict["url"] as String
        dataFound.text = someData
    }

Now if you run the program you should see the label change, that is if you wait long enough for it. Strangely, the UI thread does not update itself all that often. Depending on when in the loop you update the text field this can take several seconds. All these callbacks happen on a different thread and that thread's priority is not very high compared to the main thread. Thus, slow updates. To remedy this you must grab the main thread manually like so:

    dispatch_async(dispatch_get_main_queue()) {
        self.dataFound.text = someData
    }

If there are multiple labels, you only have to do this on the last of them, as the UI will call update on all of them. Updating labels is pretty easy, but this same paradigm could be used to update a table, images, drive animations, or manually call a page turn. For the page turn, remember you will have to stop the preset (assuming you are using storyboards) segue via calling shouldPerformSegueWithIdentifier. When you run the code now, it should update the UI at such a rapid rate that you never see the “No Data” default label. Of course, in a real app this would be a spinning or wait animation that would be stopped in the didReceiveAPIResults.

The above code is missing a few items, namely handling JSON arrays, and error handling. Hopefully, this will help you develop your next Swift project.

All source code found at: https://github.com/makeandbuild/SwiftApiBlog