Develop a iOS Swift CRUD App with a REST backend

Apple has introduce a new programming language for Cocoa and Cocoa touch called Swift. The syntax of this new language is a lot more familiar to developers that work on languages such as Visual Basic, Scala and many more. This comes to a refresh language different than Objective-C which has a complex syntax that takes a high learning curve even for C++ or Java developers.

Swift is a modern programming language that maintains many features of Objective-C using a clearer syntax. The programming paradigms provided by Swift include Objective Oriented, Imperative and Functional Programming. For more details please check the iBook here.

Unfortunately for now you have to download and Install OSX 10.9.3 or later, and Xcode 6 Beta 5 from your developer account to be able to develop your app.

On this posts we will show you how to build an app that communicates with the REST Server develop on Node.js. We will also show you how to use Objective-C libraries using cocoa-pods.

Create a new Swift Project

This section describe how to create a new project using Swift, this is actually very straightforward.
– Open Xcode 6
– Select create a new project
– Select iOS Application -> Single View Application
new_project
– Fill the information and choose Swift as a language
– Select the folder where your project will be created and finish
– Finally if you don’t want to install iOS 8 Beta on your device select deployment target to 7.0
– Run it, to see a white screen

Setup to use Objective-C Libraries

On this section we will install the CocoaPods dependency manager, setup the libraries we will use and setup our project to use them

– Install the CocoaPods Dependency manager by using the following command
sudo gem install cocoapods
– Create a Podfile on the root of the project, the same folder as the .xcodeproj file.
– Add the following line to your Podfile
platform :ios, '7.0'
pod "AFNetworking", "~> 2.0"

– Download the dependencies using the command pod install
– Now you should have a new file with the extension .xcworkspace open it, you can use the command line open PeopleAdmin.xcworkspace
– Go to the Target -> Build Settings and find Swift Compiler – Code Generation
– Add a user defined setting Objective-C Bridging Header
Screen Shot 2014-08-17 at 3.05.03 PM
– Now set the name where you put the code, in our case the file is Bridging-Header.h
– Go to the navigator and create a new file
– Select iOS->Source->Header File named as you put the settingBridging-Header.h
– Add the line #import <AFNetworking/AFNetworking.h>

Now you are ready to develop your app

Create the Views

– Go to the file Main.storyboard
– Add a new table view, and a table view cell
– Set a title and subtitle
tableView

– Add a new View Controller, that will be the Person Details View
– Add a Navigation Bar with a Back Button
– Pressing the Ctrl key select the button and while maintaining the key drag to the view controller with the table and select Action Segue->Show
– Do the same from the Table View Cell to the Person Details View
– Add a Toolbar with three new buttons: 1)Update, New and Delete
– Finally add six(6) labels and four(4) text fields as shown on the following image:
personview
– Create a new Swift file called PersonViewController that implements UIViewController
– On the Storyboard select the view controller and modify the custom calls to the PersonViewController

personViewController

– You should be able to run your app right now.

Connect Views to the Code

Finally we will implement the code that allow us to provide the necessary functionality to our app

People Connector

We create a new class call PeopleConnector that connects to the rest server and gets a list of people

– Add a protocol so we can send the async results to the table view

protocol PeopleConnectorProtocol{
    func didReceiveList(results:NSArray)
}

-Then create the class with the properties and protocol, the ‘?’ symbol means is optional.
class PeopleConnector{
    
    var delegate:PeopleConnectorProtocol?
    let manager:AFHTTPRequestOperationManager
    
    init(){
    }
    func list(){
    }
}

– On the View Controller implement the Table View Data Source UITableViewDelegate and the Protocol we just write
– Init all the properties we will require to show the data on the table view, and to show the details of the person we select
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,PeopleConnectorProtocol {

    @IBOutlet var appsTableView:UITableView!
    let kCellIdentifier: String = "SearchResultCell"
    var tableData:NSArray!
    var api:PeopleConnector!
    var personSelected:NSDictionary!
    var refreshControl:UIRefreshControl!

    override func viewDidLoad() {
        super.viewDidLoad()
        api = PeopleConnector()
        tableData = []
        self.api.delegate = self
        api.list()
    }

– Now implement the necessary functions to fill up the table data based on the array, right now the array is empty since we have not implement the call on the PeopleConnector
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell
        
        //Get the values from the Json object inside the array 
        var person = tableData[indexPath.row]as NSDictionary
        var name = person["NAME"] as NSString
        var lastname = person["LASTNAME"] as NSString
        var city = person["CITY"] as NSString
        var country = person["COUNTRY"] as NSString
        
        cell.textLabel.text = "\(name) \(lastname)"
        cell.detailTextLabel.text = "\(country), \(city)"
        
        return cell
    }

– We need to add the implement the method the connector will call when finish, this will get all the data asynchronous from the server
func didReceiveList(results: NSArray) {
        dispatch_async(dispatch_get_main_queue(), {
            self.tableData = results
            self.appsTableView!.reloadData()
            self.refreshControl.endRefreshing()
        })
    }

– Now lets go to the Story Board and Connect the text fields Outlets using the assistant editor
– Select each text field and holding the ctrl key drag it into the PersonViewController Class
addoutlets
– Init the view with the information that was send from the ViewController
 var api:PersonConnector!

    var person:NSDictionary!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        api = PersonConnector()
        var id = person["ID"] as NSInteger
        tId.text = String(id)
        tName.text = person["NAME"] as NSString
        tLastname.text=person["LASTNAME"] as NSString
        tCity.text=person["CITY"] as NSString
        tCountry.text=person["COUNTRY"] as NSString
    }
    
    override func didReceiveMemoryWarning() {
    }


– The last part of the class is to create the buttons actions and them prepare the data to be send to the server
NOTE: We have some problems with node.js since the key names on the JSON are case sensitive so we modify the server to read uppercase Json keys
  @IBAction func bUpdate(sender: AnyObject) {
        var newPerson:NSDictionary = ["NAME":tName.text,
            "LASTNAME":tLastname.text,
            "CITY":tCity.text,
            "COUNTRY":tCountry.text,
            "ID":tId.text
        ]
        api.update(newPerson)
    }
    @IBAction func bCreate(sender: AnyObject) {
        var newPerson:NSDictionary = ["NAME":tName.text,
            "LASTNAME":tLastname.text,
            "CITY":tCity.text,
            "COUNTRY":tCountry.text
        ]
        api.create(newPerson);
    }
    @IBAction func bDelete(sender: AnyObject) {
        var id:Int = tId.text.toInt()!
        api.delete(id)
    }

– Now we create the PersonConnector that will handle the calls to the server
import Foundation

protocol PersonConnectorProtocol{
    func didReceivePersonDetail(person:NSDictionary)
}
class PersonConnector{
    init(){
    }
    func detail(id:NSInteger){
    }
    func create(person:NSDictionary){
    }
    func update(person:NSDictionary){
    }
    func delete(id:Int){
    }
}

Connect to REST Server using AFNetworking Library

– Now lets go back to the PeopleConnector so we can implement the actual REST call to the server to get a list of people

init()
    {
        var url:NSURL = NSURL(string:"http://at3node.mybluemix.net")
        manager = AFHTTPRequestOperationManager(baseURL:url)
    }
    func list(){
        manager.GET("",
            parameters:nil,
            success:{(operation:AFHTTPRequestOperation!,responseObject:AnyObject!)in
                if responseObject.isKindOfClass(NSArray)
                {
                    self.delegate?.didReceiveList(responseObject as NSArray)
                }
            },
            failure:{(operation:AFHTTPRequestOperation!,error:NSError!)in
                println("Error:"+error.localizedDescription)
        })
    }

– As you can see we need to receive a NSArray data type from the server
– When the call is successful we use the delegate to send the data to the view
– Going back to the ViewController we add one las function that sends the person selected information to the PersonViewController
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {

        if segue.identifier=="person_detail"{
            
            var detail = segue!.destinationViewController as PersonViewController
            detail.person = personSelected
        }
    }

– To finilize we write the CRUD methods on the PersonConnector

    var delegate:PeopleConnectorProtocol?
    let manager:AFHTTPRequestOperationManager!
    
    init(){
        var url:NSURL = NSURL(string:"http://at3node.mybluemix.net")
        manager = AFHTTPRequestOperationManager(baseURL: url)
        manager.requestSerializer = AFJSONRequestSerializer()
    }
    func detail(id:NSInteger){
        manager.GET("/find/\(id)", parameters: nil,
            success: { (operation:AFHTTPRequestOperation!, response:AnyObject!) in
                println("JSON:"+response.description)
            },failure: { (operation:AFHTTPRequestOperation!, error:NSError!) in
                println("ERROR"+error.localizedDescription)
        })
        
    }
    func create(person:NSDictionary){
        manager.POST("", parameters: person, success: {(operation:AFHTTPRequestOperation!,response:AnyObject!) in
            println("JSON:"+response.description)
            },
            failure:{(operation:AFHTTPRequestOperation!,error:NSError!) in
                println("ERROR:"+error.localizedDescription)
        })
    }
    func update(person:NSDictionary){
        manager.PUT("", parameters: person,
            success: { (operation:AFHTTPRequestOperation!, response:AnyObject!) in
                println("JSON:"+response.description)
            },failure: { (operation:AFHTTPRequestOperation!, error:NSError!) in
                println("ERROR"+error.localizedDescription)
        })
        
    }
    func delete(id:Int){
        manager.DELETE("/\(id)", parameters: nil,
            success: { (operation:AFHTTPRequestOperation!, response:AnyObject!) in
                println("JSON:"+response.description)
            },failure: { (operation:AFHTTPRequestOperation!, error:NSError!) in
                println("ERROR"+error.localizedDescription)
        })
    }

Conclusions

In general the app is missing a few features of usability but you have an idea how to start using Swift with your old Objective-C libraries.

We think Swift is a great new language that we need to learn a lot more, but at the end will help new developers to learn fast a very powerful language.

Code

You can find the code in our github repository.

Please don’t hesitate to write your comments or ask your questions at info@advteknology.com

References

http://jamesonquave.com/blog/developing-ios-apps-using-swift-tutorial/
https://medium.com/@aommiez/afnetwork-integrate-swfit-80514b545b40

Leave a Reply