Getting to know Alamofire, SwiftJSON — iOS Swift in Xcode 11

Adonis Shingi Rumbwere
6 min readJul 20, 2020

--

If you are a beginner or intermediate iOS developer, dealing with Network calls and handling JSON data can be a daunting task. Thanks to Alamofire Software Foundation and SwiftyJSON for these two awesome libraries.

Alamofire is a library to elegantly handle HTTP connections, and SwiftyJSON is a library to elegantly serialize JSON into Swift objects. You don’t need SwiftyJSON to serialize JSON in swift, but it can get ugly having to deal with optionals.

In this tutorial we are going to build a small iOS Contacts App, using a contacts API from our friends at Android Hive https://api.androidhive.info/contacts/.

What we are going to LEARN: How to use Alamofire with SwiftyJSON to hit an API and fetch results, parse them, and show the results in an UITableViewController. We will also learn how to segue to the next view controller and set variables from the previous view controller.

Without further ado, let’s dive into it: let's create a new single view app XCode Project and install CocoaPods or Pods(these words are used interchangeably): To install Pods in your project, navigate to your root project directory using terminal and run the following commands in order.

pod init

The above command will initialize the Podfile, Once you have initialized the Podfile, you need to open the file using the following command

open Podfile

The above command will open the Podfile, Add these pods on the podfile, right below #Pods for [Your Project Name]

pod 'SwiftyJSON'
pod 'Alamofire', '~> 4.5'

Use the following command to install the above pods.

pod install
This is how your podcast file should look like after successfully installing pods
This is how your podcast file should look like after successfully installing pods

Once you have managed to add Alamofire and SwiftyJSON pods into your project, you may close the current project XCode environment and open it using the newly created workspace file in the project folder.

Open the highlighted project workspace file. Note: From now you have to use the .xcworkspace to open your project.

Let's go to the main storyboard file and add Navigation Controller onto our main view controller called contactsViewController. We will also add a table view on the contactsViewController storyboard file and add zero constraints on the contactsTableView for it to fill the whole contactsViewController.

At the point, I assume you have created two storyboards view controllers, one that houses the contacts in a table view, the contactsViewController, and the other one that houses the contacts details which we will name contacts Details ViewController as depicted in the image above. Let’s get out hands dirty with code, let's create Utils.swift. Swift file that houses our base URL and contacts endpoint and also a completion handler.

import Foundationlet API_BASEURL = "http://api.androidhive.info/"let API_CONTACTS = API_BASEURL+"contacts/"typealias DownloadComplete = () ->()

Let’s create our contacts model, I have named it Contacts.swift, this section is opinionated. You would notice that I have imported SwiftyJSON into contacts model and created a class that houses contacts private variables and initialization methods.

import Foundation
import SwiftyJSON
class Contacts {

private var _id:String!
private var _name: String!
private var _email: String!
private var _address: String!
private var _gender:String!
private var _mobile:String!


var id:String {
if _id == nil {
_id = ""
}

return _id
}

var name:String! {
if _name == nil {
_name = ""
}

return _name
}

var email:String {
if _email == nil {
_email = ""
}

return _email
}
var address:String {
if _address == nil {
_address = ""
}

return _address
}

var gender:String {
if _gender == nil {
_gender = ""
}

return _gender
}

var mobile:String{
if _mobile == nil{
_mobile = ""
}

return _mobile
}

init(contactDict: JSON) {
self._id = contactDict["id"].stringValue
self._name = contactDict["name"].stringValue
self._address = contactDict["address"].stringValue
self._email = contactDict["email"].stringValue
self._mobile = contactDict["phone"]["mobile"].stringValue
self._gender = contactDict["gender"].string
}

}

Let’s go on and create the ContactsViewController.swift and create a contacts array of the type Contacts Model, We will append contacts data coming from API into this array and use it to populate our table view stubs.

Let’s jump straight and talk about the ContactsAPICalling function a little bit, You can notice that this function has a completion handler that will help us to know when the contacts data has been fully downloaded so that we can reload the table view.

We then fired a GET request to our contacts endpoint without headers and got the responseJson as contact response and then assigned the response result into the result variable. The line below shows how to grab all contact data from the “contacts” array of the contacts endpoint.

let contactsJSON = JSON(result.value!)["contacts"]
Android Hive Contacts API Postman Snapshot
import UIKit
import Alamofire
import SwiftyJSON
class ContactsViewController: UIViewController {

var contacts = [Contacts]()

@IBOutlet weak var contactsTableView: UITableView!

override func viewDidLoad() {
super.viewDidLoad()

contactsTableView.dataSource = self
contactsTableView.delegate = self


self.ContactsAPICalling {
print("Contacts Downloaded")
self.contactsTableView.reloadData()
}
}

func ContactsAPICalling(completed: @escaping DownloadComplete){

Alamofire.request(API_CONTACTS, method: .get, encoding: JSONEncoding.default, headers: nil).responseJSON { (contactsResponse) in

let result = contactsResponse.result
let contactsJSON = JSON(result.value!)["contacts"]

print(contactsJSON)

for i in 0..<contactsJSON.count {

let allContacts = Contacts(contactDict: contactsJSON[i])

self.contacts.append(allContacts)
}

completed()

}

}
}

Let’s create an extension of ContactViewController to handle the contacts data and interaction of the table view through UITableViewDataSource and UITableViewDelegate. The “contacts.count” will populate the number of contacts on the number of rows in the section table view stub.

We will then use the CellForRowAt table view function to registers our table view cell, you will notice that we did not create a custom cell rather we used the inbuilt UITableViewCell style subtitle with the reusable identifier “contactscell”. From this point, it becomes easier to populate our cell two labels as seen below.

On the didSelectRowAt, we will then perform a segue to navigate to our contactsDetailsViewController through a segue identifier “toContactsView”. From this point, we will need to pass the contacts variable onto our destination View Controller to able to populate the selected row contact details on the next view controller.

extension ContactsViewController: UITableViewDataSource,UITableViewDelegate {

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

contactsTableView.register(UITableViewCell.self, forCellReuseIdentifier: "contactscell")

var cell = contactsTableView.dequeueReusableCell(withIdentifier: "contactscell")

if cell == nil {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "contactscell")
}

cell?.textLabel?.text = contacts[indexPath.row].name
cell?.detailTextLabel?.text = contacts[indexPath.row].email

return cell!

}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "toContactsView", sender: self)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationVC = segue.destination as? ContactDetailsViewController {

destinationVC.contactDetails = contacts[(contactsTableView.indexPathForSelectedRow?.row)!]
contactsTableView.deselectRow(at: contactsTableView.indexPathForSelectedRow!, animated: true)

}
}

}

Let’s finish up the last part of the projects by segueing to ContactDetailsViewController which houses contact details IBOutlets. We will use the contactDetails variable to populate the contact outlets in viewDidLoad function.

import UIKitclass ContactDetailsViewController: UIViewController {

var contactDetails:Contacts!

@IBOutlet weak var FullNameLbl: UILabel!
@IBOutlet weak var MobileNumberLbl: UILabel!
@IBOutlet weak var AddressLbl: UILabel!
@IBOutlet weak var EmailLbl: UILabel!
@IBOutlet weak var GenderLbl: UILabel!

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.

FullNameLbl.text = contactDetails.name
MobileNumberLbl.text = contactDetails.mobile
AddressLbl.text = contactDetails.address
EmailLbl.text = contactDetails.email
GenderLbl.text = contactDetails.gender
}
}

Here is the Github Repository Link to the project https://github.com/TheDoer/Alamofire-SwiftyJSON-Tutorial

--

--