-2

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.

user6631314
  • 1,751
  • 1
  • 13
  • 44

1 Answers1

2

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)
}
PGDev
  • 23,751
  • 6
  • 34
  • 88
  • This worked. Wondering, however, why in this case, this is necessary? is it because the currencies are not in an array? – user6631314 Jul 01 '20 at 14:18
  • 1
    But yes, in the example above the currencies are returned in a dictionary of the form `[String: BitcoinQuoteReturned]`, which is why that type needs to be decoded. If they were returned in an array, you would use `[BitcoinQuoteReturned]` to decode the array. Decoding just `BitcoinQuoteReturned` means you expect the response to contain a single instance of that object. – bplattenburg Jul 01 '20 at 17:24