After some experimentation my Playground looks as follows:
import Cocoa
import Foundation
let jsonData = """
{
"USD_AFN": 70.129997,
"USD_AUD": 1.284793,
"USD_BDT": 82.889999,
"USD_BRL": 3.418294,
"USD_KHR": 4004.99952
}
""".data(using: .utf8)!
do {
let obj = try JSONSerialization.jsonObject(with:jsonData, options:[])
print(obj) // this is an NSDictionary
if let dict = obj as? [String:Double] {
print(dict) // This is not "just" a cast ... more than I thought
}
}
struct CurrencyRate: Codable {
var results : [String:Double]
}
// If you use a "results"-key it _must_ be present in your JSON, but it would allow to add methods
let resultsJson = """
{
"results" : {
"USD_AFN": 70.129997,
"USD_AUD": 1.284793,
"USD_BDT": 82.889999,
"USD_BRL": 3.418294,
"USD_KHR": 4004.99952
}
}
""".data(using: .utf8)!
do {
let currencyRate = try JSONDecoder().decode(CurrencyRate.self, from: resultsJson)
print(currencyRate)
}
// this is probably the easiest solution for just reading it
do {
let rates = try JSONDecoder().decode([String:Double].self, from:jsonData)
print(rates)
}
// While you could do the following it does not feel "proper"
typealias CurrencyRatesDict = [String:Double]
extension Dictionary where Key == String, Value == Double {
func conversionRate(from:String, to:String) -> Double {
let key = "\(from)_\(to)"
if let rate = self[key] {
return rate
} else {
return -1.0
}
}
}
do {
let currRates = try JSONDecoder().decode(CurrencyRatesDict.self, from:jsonData)
print(currRates)
print(currRates.conversionRate(from:"USD", to:"AUD"))
}
This taught me a few things. I would not have thought that a NSDictionary
(which is produced by JSONSerialization.jsonObject
automatically and has no types) converts this easily into a [String:Double]
, but of course it might fail and you should write some error handling to catch it.
Your CurrencyRate
struct
would have the advantage to allow easy extensions. Since Dictionaries are structs
it is not possible to derive from them. As the last version illustrates it is possible to add a conditional extension to a Dictionary
. However this would add your new function to any Dictionary
matching the signature which might be acceptable in many cases even though it 'feels' wrong from the design perspective.
As you can see there is a whole bunch of ways to deal with this in Swift. I would suggest you use the Codable
protocol and an additional key. Most probably there are "other things" you will want to do with your object.