Search code examples
jsonswiftjsondecoder

Syntax to access decoded JSON dictionary items in Swift


I am trying to decode some JSON but struggling with how to access the items in the JSON.

The JSON looks like this and JSONlint confirms it is valid json

{
  "USD" : {"15m" : 9161.16, "last" : 9161.16, "buy" : 9161.16, "sell" : 9161.16, "symbol" : "$"},
  "EUR" : {"15m" : 8175.89, "last" : 8175.89, "buy" : 8175.89, "sell" : 8175.89, "symbol" : "€"},
  "JPY" : {"15m" : 985609.11, "last" : 985609.11, "buy" : 985609.11, "sell" : 985609.11, "symbol" : "¥"}
}

app.quicktype.io suggests this struct for decoding but does not have a variable for the currency:

struct BitcoinQuoteReturned: Codable {
    let the15M, last, buy, sell: Double
    let symbol: String

    enum CodingKeys: String, CodingKey {
        case the15M = "15m"
        case last, buy, sell, symbol
    }
}

Non working Code:

let myquote = try? JSONDecoder().decode(BitcoinQuoteReturned.self, from: data)                           
if let aquote = myquote {
let usdquote = aquote.USD//ERROR
}

When I try to decode in Swift, I can't figure out how to access a specific currency. aquote.USD gives a class has no member error while aquote["USD"] and aquote[1] give no subscript members errors. How can I access the USD line in the JSON?

Thanks for any suggestions.


Solution

  • Use [String:BitcoinQuoteReturned].self instead of BitcoinQuoteReturned while parsing, i.e.

    let myquote = try? JSONDecoder().decode([String:BitcoinQuoteReturned].self, from: data) //here...
    if let aquote = myquote {
        let usdquote = aquote["USD"]
        print(usdquote)
    }
    

    Note: Use a do-catch statement when calling decode(_:from:) and in catch statement print the whole error. This will give you a detailed description of where the issue exist when parsing.

    do {
        let myquote = try JSONDecoder().decode([String:BitcoinQuoteReturned].self, from: data)
        let usdquote = myquote["USD"]
        print(usdquote)
    } catch {
        print(error)
    }