How to fetch exchange rate from internet API in iOS swift

This tutorial has been updated for X code 7.3.1 & swift 2.3

The app is supposed to make solution easier for user but I still see many apps that force you to add exchange rate manually. App user has to go through extra step each time to find exchange rate & add manually. It would be lot easier for user if you can fetch exchange rate automatically from internet.
The user has to download app over internet there is no way around that. On first launch after install you can fetch exchange rate from internet. Then save it for offline use. You could use my tutorial on NSUserDefaults to save key value pair.

1. First lets set up the x code project as usual. Create new single view application X code project. Set project name to exchange rates & save it on desktop.

new x code project

2. Go to main storyboard, delete view controller & add table view controller

add tableview controller

3. Select table view controller & set it as initial view controller

is initial view controller

4. Select the prototype cell & set its identifier to tableCell

prototype cell identifier

5. Select table view controller, go to Editor -> Embed In -> Navigation controller

add navigation bar

6. Now delete view controller swift file & add new cocoa touch class file of subclass UITableViewController

cocoa touch class

7. Go to main storyboard, select table view controller & set custom class to RatesTableViewController

set custom class

8. Create empty array of string to store exchange rates as follows

class RatesTableViewController: UITableViewController {
// 8
var exchangeRates = [String]()

9. Set number of sections to 1 & set number of rows per section to exchange rate count as follows

// MARK: - Table view data source
// 9
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return exchangeRates.count
}

10. Uncomment cell for row at index path & show all items in array on table view as follows

// 10
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath)

    // Configure the cell...
    cell.textLabel?.text = exchangeRates[indexPath.row]

    return cell
}

11. In view did load create url request & session as follows

override func viewDidLoad() {
    super.viewDidLoad()

    // 11
    let apiEndPoint = "https://api.fixer.io/latest"

    guard let url = NSURL(string: apiEndPoint) else {
        print("Url is not valid")
        return
    }

    let urlRequest = NSURLRequest(URL: url)

    let session = NSURLSession.sharedSession()

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

12. Now we are going to create data task request as follows

    let session = NSURLSession.sharedSession()
    // 12
    let task = session.dataTaskWithRequest(urlRequest) { (data, response, error) in
        // 1
        guard error == nil else {
            print(error?.localizedDescription)
            return
        }
        // 2
        if let httpResponse = response as? NSHTTPURLResponse {
            //3
            if httpResponse.statusCode == 200 {
                print("Everything is ok")
            }
            else {
                print("Error fetching data")
            }
        }
        // 4
        guard let data = data else {
            print("No data received")
            return
        }
    }
    // 5
    task.resume()

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
  1. If the error is not nil then print out the error & stop executing rest of the code.
  2. If the response is of type http url response then unwrap the optional
  3.  If response code is 200 then everything went smoothly otherwise there is some error that needs to be fixed.
  4.  If no data is received from server then stop executing rest of the code.
  5.  Task stars with suspended state. So to actually execute task you need to resume the task.

13. The data we received is in JSON format & now we will convert into dictionary. For that import foundation as follows

import UIKit
// 13
import Foundation

14. Convert JSON data into dictionary & print out if there is error & print out the dictionary as follows

        // 4
        guard let data = data else {
            print("No data received")
            return
        }
        // 14
        do {
            guard let exchangeDict = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject] else {
                print("Could not convert JSON to dictionary")
                return
            }
            print(exchangeDict.description)
        }
        catch {
            print("Error trying to convert JSON to dictionary")
        }
    }
    // 5
    task.resume()

15. Now take information out of dictionary & put it into table. And update table view as follows

            print(exchangeDict.description)
            //15
            // 1
            if let rates = exchangeDict["rates"] {
                // 2
               let currencies = ["AUD", "BGN", "BRL", "CAD", "CHF", "CNY", "CZK", "DKK", "GBP", "HKD", "HRK", "HUF", "IDR", "ILS", "INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PLN", "RON", "RUB", "SEK", "SGD", "THB", "TRY", "USD", "ZAR"]
                // 3
                for currency in currencies {
                    if let rate = rates[currency] as? Float {
                        self.exchangeRates.append("1 EUR = \(rate) " + currency)
                    }
                }
                // 4
                NSOperationQueue.mainQueue().addOperationWithBlock({ 
                    self.tableView.reloadData()
                })
            }
            // 5
            if let date = exchangeDict["date"] as? String {
                NSOperationQueue.mainQueue().addOperationWithBlock({ 
                    self.navigationController?.navigationBar.topItem?.title = "Updated on " + date
                })
            }
        }
        catch {
            print("Error trying to convert JSON to dictionary")
        }
    }
  1. First unwrap exchange rates from dictionary
  2.  Create array of currencies
  3. Go through each currency & add rate to array
  4. Everything in networking happens in background queue but you should update the table on main queue
  5. Get the date & update navigation title on main queue

16. Now build and run app in iPhone 5s & you will see the following exchange rate

exchange rate app
Download X code file
Challenge 1: Fetch exchange rate for all currencies for 1 USD

usd exchange rate
Download Challenge 1 Solution
Challenge 2: Fetch exchange rate between only USD & INR & between USD & EUR.

USD, INR, EUR
Download Challenge 2 Solution

Total 2 Votes
0

Tell us how can I improve this tutorial?

+ = Verify Human or Spambot ?