这里和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
}
}
}
这里有什么我明显错的吗?
如果我的格式很糟糕,请提前感谢您的帮助!
答案 0 :(得分:1)
尝试使用以下模型,这可行 - bpi
和USD
都不是数组,只是单个值:
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"
}
}