Swift 4中的JSON解析帮助 - 数据结构问题?

时间:2017-11-02 08:19:28

标签: ios json swift

这里和Swift的新功能,所以请放轻松我......

尝试解析包含嵌套字典的JSON时有点卡住。我认为我创建的数据结构有问题,我试图纠正但仍然遇到同样的问题。

这是我正在尝试使用的JSON API: https://api.coindesk.com/v1/bpi/currentprice.json

这些是我为此建模的数据结构:

struct base: Decodable {

    let disclaimer: String
    let bpi: [Bpi]
}

struct Bpi: Decodable {
    let USD: [USD]
}

struct USD: Decodable {
    let rate_float: Float
}

这是我在VC中的代码:

 override func viewDidLoad() {
     super.viewDidLoad()

     let jsonURLString = "https://api.coindesk.com/v1/bpi/currentprice.json"

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

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

         guard let data = data else {return}

         do {
             let bitcoinData = try JSONDecoder().decode(base.self, from: data)
             print(bitcoinData.bpi)
         } catch {
             print("error")
         }

    } .resume()  // Fires off the session
}

我可以从免责声明字符串或根字典中的其他字符串中获取数据,但就是这样。我无法用嵌套的dictonaries进一步解析任何东西 - 它只是抛出了catch错误。

这是JSON:

{
    "time": {
        "updated": "Nov 2, 2017 06:08:00 UTC",
        "updatedISO": "2017-11-02T06:08:00+00:00",
        "updateduk": "Nov 2, 2017 at 06:08 GMT"
    },
    "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org",
    "chartName": "Bitcoin",
    "bpi": {
        "USD": {
            "code": "USD",
            "symbol": "$",
            "rate": "6,889.4013",
            "description": "United States Dollar",
            "rate_float": 6889.4013
        },
        "GBP": {
            "code": "GBP",
            "symbol": "£",
            "rate": "5,184.4053",
            "description": "British Pound Sterling",
            "rate_float": 5184.4053
        },
        "EUR": {
            "code": "EUR",
            "symbol": "€",
            "rate": "5,910.4587",
            "description": "Euro",
            "rate_float": 5910.4587
        }
    }
}

这里有什么我明显错的吗?

如果我的格式很糟糕,请提前感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

尝试使用以下模型,这可行 - bpiUSD都不是数组,只是单个值:

struct base: Decodable {

    let disclaimer: String
    let bpi: Bpi
}

struct Bpi: Decodable {
    let USD: USD
}

struct USD: Decodable {
    let rate_float: Float
}

答案 1 :(得分:0)

如果通用类型Dictionary<K,V>Decodable都可解码,则

词典(K)会隐式V符合。

假设您为货币

创建结构Coin
struct Coin: Decodable {

    private enum CodingKeys : String, CodingKey {
        case code, symbol, rate, description, rateFloat = "rate_float"
    }

    let code : String
    let symbol : String
    let rate : String
    let description : String
    let rateFloat : Float
}

您可以轻松将货币词典解码为[String:Coin],而无需任何其他代码

struct Base: Decodable {

    private enum CodingKeys : String, CodingKey {
        case disclaimer, coins = "bpi"
    }

    let disclaimer: String
    let coins: [String:Coin]
}

并使用它

let bitcoinData = try JSONDecoder().decode(Base.self, from: data)
print(bitcoinData.coins)

或者,如果您希望将货币设为Coin数组,则可以编写自定义初始值设定项并将字典值映射到数组。

此示例还解码updatedISO字典

中的time
struct Base: Decodable {

    struct Time : Decodable {

        private enum CodingKeys : String, CodingKey {
            case updated = "updatedISO"
        }

        let updated : Date
    }

    private enum CodingKeys : String, CodingKey {
        case disclaimer, bpi, time
    }

    let disclaimer: String
    let coins: [Coin]
    let updated : Date

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        disclaimer = try container.decode(String.self, forKey: .disclaimer)
        let bpi = try container.decode([String:Coin].self, forKey: .bpi)
        coins = Array(bpi.values.sorted(by: {$0.code < $1.code}))
        let time = try container.decode(Time.self, forKey: .time)
        updated = time.updated
    }
}

并使用此示例

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let bitcoinData = try decoder.decode(Base.self, from: data)
print(bitcoinData.coins)

答案 2 :(得分:0)

你宣布你的bpi&amp;使用属性作为数组,但它们是字典(嵌套的json对象)。如果您有样本JSON,可以在下次尝试使用此转换器:https://danieltmbr.github.io/JsonCodeGenerator/

它会生成以下输出:

struct Root: Codable {

  let time: Time
  let disclaimer: String
  let chartName: String
  let bpi: Bpi

}

struct Time: Codable {

  let updated: String
  let updatedISO: String
  let updateduk: String

}

struct Bpi: Codable {

  let USD: USD
  let GBP: USD
  let EUR: USD

}

struct USD: Codable {

  let code: String
  let symbol: String
  let rate: String
  let description: String
  let rateFloat: Double

  private enum CodingKeys: String, CodingKey {
    case code
    case symbol
    case rate
    case description
    case rateFloat = "rate_float"
  }
}