I am trying to build an app that displays Currency exchange rates using the Alpha Vantage API for iOS. I have built the functions but can\'t figure out how to access the exact j
The main error is that the value for key 5. Exchange Rate
is String
not Float
and the code crashes reliably when being force unwrapped.
In Swift 4 the Decodable
protocol is much more convenient than a dictionary.
Create two structs. The ExchangeRate
struct contains a computed property floatRate
to return the Float
value
struct Root : Decodable {
let exchangeRate : ExchangeRate
private enum CodingKeys: String, CodingKey { case exchangeRate = "Realtime Currency Exchange Rate" }
}
struct ExchangeRate : Decodable {
let fromCode, fromName, toCode, toName, rate : String
let lastRefreshed, timeZone : String
private enum CodingKeys: String, CodingKey {
case fromCode = "1. From_Currency Code"
case fromName = "2. From_Currency Name"
case toCode = "3. To_Currency Code"
case toName = "4. To_Currency Name"
case rate = "5. Exchange Rate"
case lastRefreshed = "6. Last Refreshed"
case timeZone = "7. Time Zone"
}
var floatRate : Float {
return Float(rate) ?? 0.0
}
}
Then make the download function more versatile by passing from and to currency as parameters. This version uses the JSONDecoder
and returns either the ExchangeRate
instance or the Error
func downloadRate(from: String, to: String, completionHandler: @escaping (ExchangeRate?, Error?) -> Void) {
let urlString = "https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=\(from)&to_currency=\(to)&apikey=NP3M8LL62YJDO0YX"
let task = URLSession.shared.dataTask(with: URL(string: urlString)!, completionHandler: { data, response, error in
if error != nil {
completionHandler(nil, error!)
} else {
do {
let result = try JSONDecoder().decode(Root.self, from: data!)
completionHandler(result.exchangeRate, nil)
} catch {
completionHandler(nil, error)
}
}
})
task.resume()
}
and use it
func usdQUotesRequest() {
USDClient().downloadRate(from:"USD", to: "EUR") { exchangeRate, error in
if let exchangeRate = exchangeRate {
self.usdtoeurquote = exchangeRate.floatRate
DispatchQueue.main.async {
self.stopActivityIndicator()
self.Refresh.isEnabled = true
}
} else {
DispatchQueue.main.async {
self.displayAlert("Unable to Retrieve Latest Conversion Rates", message: "\(error!)")
self.stopActivityIndicator()
self.Refresh.isEnabled = true
}
}
}