如何使用带突变键的可编码解码JSON?

时间:2018-09-28 13:29:17

标签: ios json swift struct codable

我需要解码以下格式的JSON:

{
 "rates": {
"btc": {
  "name": "Bitcoin",
  "unit": "Ƀ",
  "value": 0,
  "type": "crypto"
},
"eth": {
  "name": "Ether",
  "unit": "Ξ",
  "value": 29.658,
  "type": "crypto"
},
"bch": {
  "name": "Bitcoin Cash",
  "unit": "BCH",
  "value": 12.3,
  "type": "crypto"
},
"ltc": {
  "name": "Litecoin",
  "unit": "Ł",
  "value": 108.219,
  "type": "crypto"
}...}

我目前得到这样的数据,我对此感到不满意:

import Foundation

class CGExchange {

static let shared = CGExchange()

var defaultCurrency = UserDefaults.standard.value(forKey: "DefaultCurrency")!

struct Rates: Codable {
    let rates: Currency
}

struct Exchange: Codable {

    let name: String
    let value: Double
    let unit: String

}

struct Currency: Codable {

    let btc: Exchange
    let eth: Exchange
    let bch: Exchange
    let ltc: Exchange
    let usd: Exchange
    let aed: Exchange
    let ars: Exchange
    let aud: Exchange
    let bdt: Exchange
    let bhd: Exchange
    let bmd: Exchange
    let brl: Exchange
    let cad: Exchange
    let chf: Exchange
    let clp: Exchange
    let cny: Exchange
    let czk: Exchange
    let dkk: Exchange
    let eur: Exchange
    let gbp: Exchange
    let hkd: Exchange
    let huf: Exchange
    let idr: Exchange
    let ils: Exchange
    let inr: Exchange
    let jpy: Exchange
    let krw: Exchange
    let kwd: Exchange
    let lkr: Exchange
    let mmk: Exchange
    let mxn: Exchange
    let myr: Exchange
    let nok: Exchange
    let nzd: Exchange
    let php: Exchange
    let pkr: Exchange
    let pln: Exchange
    let rub: Exchange
    let sar: Exchange
    let sek: Exchange
    let sgd: Exchange
    let thb: Exchange
    let `try`: Exchange
    let twd: Exchange
    let vef: Exchange
    let zar: Exchange
    let xdr: Exchange
    let xag: Exchange
    let xau: Exchange

}

var exchangeData = [Rates]()

func getData(arr: Bool, completion: @escaping (Bool) -> ()) {
    /// alamofire / urlsession request
    let urlJSON = "https://api.coingecko.com/api/v3/exchange_rates"

    guard let url = URL(string: urlJSON) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, err) in

        guard let data = data else { return }

        do {

//                let currencies = try JSONDecoder().decode(Currency.self, from: data)
            let exchanges = try JSONDecoder().decode(Rates.self, from: data)
            self.exchangeData = [exchanges]

            print(self.exchangeData)
            completion(arr)

        } catch let jsonErr {
            print("error serializing json: \(jsonErr)")

        }

        }.resume()

}

func refresh(completion: () -> ()) {
    defaultCurrency = UserDefaults.standard.string(forKey: "DefaultCurrency")!
    completion()
}

}

问题是我只需要“费率”中保留的3个标题中的值,但这取决于用户选择确定的UserDefaults值。 IE,如果用户选择GBP作为他们的defaultCurrency,我只需要从结构货币中获取let gbp,但是获取该值很尴尬,因为我无法更改它。即在我的DataViewController中获取数据let exchangeRate = CGExchange.shared.exchangeData[0].rates.gbp.value,但理想情况下,我需要根据默认货币是哪种结构进行更改。即let exchangeRate = CGExchange.shared.exchangeData[0].rates.defaultCurrency.value

但是我正在努力寻找我该怎么做。 如果我可以使用可以更改的值制作结构,例如:

struct Currency: Codable {
    let dc: Exchange
    let sc: Exchange
    let tc: Exchange

    enum CodingKeys: String, CodingKey {
        case dc = "\(defaultCurrency)"
        case sc = "\(secondCurrency)"
        case tc = "\(currency)"

    }

}

基本上这就是我所需要的,但它说:“枚举大小写的原始值必须是文字”

有什么建议吗?谢谢。

1 个答案:

答案 0 :(得分:1)

您可以尝试

struct Rates: Codable {
  let rates: [String:Exchange]
}

struct Exchange: Codable {

  let name: String
  let value: Double
  let unit: String 
}

然后使用

let defCurrency = <#setHere#> // "btc"
let ex =  CGExchange.shared.exchangeData[0].rates[defCurrency]