ios - 如何解码这个特定的 JSON 模型?
问题描述
编辑2:
在更改模型结构并在没有完成处理程序的情况下调用 JSON 解码器之后,我设法让它工作。谢谢大家的帮助。
固定代码:
模型
import Foundation
struct RatesResponse: Decodable, Hashable{
let rates: [String: Double]
}
解码器类
import Foundation
class RatesModelData{
public var rateCurrency = [String]()
public var rateValue = [Double]()
public func getRates(currency: String){
guard let url = URL(string: "https://api.exchangerate.host/latest?base=\(currency)")
else {
print("URL is invalid")
return
}
var request = URLRequest(url: url)
let dataTask = URLSession.shared.dataTask(with: request){data, response, error in
if let data = data {
do{
let ratesResponse = try JSONDecoder().decode(RatesResponse.self, from: data)
for rate in ratesResponse.rates{
self.rateCurrency.append(rate.key)
self.rateValue.append(rate.value)
}
print(self.rateCurrency)
} catch {
print(error)
}
}
}
dataTask.resume()
}
}
编辑:
我已将 let rate = Rates 更改为 let rates = Rates,将解码器类修改为以下内容并添加了一个 do/catch 语句,但是我现在收到错误“给定的数据是无效的 JSON”。我也更新了代码片段。
我有这个 json 模型:
https://api.exchangerate.host/latest?base=usd
而且我一生都无法弄清楚如何正确解码它。我知道它是一本字典,因此必须对其进行解码,但我正在努力解决我做错的事情。
模型:
struct RatesResponse: Decodable, Hashable{
let rates : Rates
}
struct Rates: Decodable, Hashable {
let rates: [String: Double]
}
解码器类:
class RatesModelData{
public func getRates(currency: String, _ completionHandler: @escaping(Rates) -> Void){
guard let url = URL(string: "https://api.exchangerate.host/latest?base=\(currency)")
else {
print("URL is invalid")
return
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "ACCEPT")
let dataTask = URLSession.shared.dataTask(with: request){data, response, error in
do{
if let data = data {
if let ratesResponse = try JSONDecoder().decode(RatesResponse?.self, from: data){
completionHandler(ratesResponse.rates)
}
return
}
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else{
print("Error with response: \(response)")
return
}
if let error = error {
print("Error Thrown : \(error)")
return
}
} catch {
print(error)
}
}
dataTask.resume()
}
}
理想情况下,我希望将其显示在列表视图(SwiftUI)中,但现在只是就我的解码出错的地方征求一些建议。
解决方案
您的对象模型表明与键关联的值rates
是具有另一个rates
键的另一个对象。但这与您提供的 JSON 不匹配。与顶级rates
键关联的值只是一个字典。
因此,您可以执行以下操作并完成它:
struct ResponseObject: Decodable {
let rates: [String: Double]
}
或者,如果您想捕获此 JSON 中的所有内容,您可以添加其他属性:
struct Motd: Decodable {
let msg: String
let url: URL
}
struct ResponseObject: Decodable {
let motd: Motd
let success: Bool
let base: String
let date: Date
let rates: [String: Double]
}
接着:
do {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let responseObject = try decoder.decode(ResponseObject.self, from: data)
print(responseObject)
} catch {
print(error)
}
FWIW、base
、date
和rates
对象可能/应该是可选的,例如:
struct ResponseObject: Decodable {
let motd: Motd
let success: Bool
let base: String?
let date: Date?
let rates: [String: Double]?
}
为了确认,我们需要看看格式良好的非成功响应是什么样的。浏览文档并不是很明显,但类似上面的内容可能是您想要的,在哪里JSONDecoder
能够成功解码成功响应和失败响应。
推荐阅读
- asp.net-core-webapi - Dot.Net Core 3.1 API 中 GetCookies 方法的扩展类是哪个?
- javascript - 可通过 Postman 调用 https Firebase Cloud Functions:“请求的 Content-Type 不正确。”
- python - 使用列表过滤第二行的数据框
- twitter - 是否可以使用 NIFI 上的 twitter API 获取某个主题中最受欢迎的推文?
- mysql - Mysql从不同表计算和排序预订日价格
- power-automate - 如何从特定 Power Platform 环境中仅删除数据库?
- java - 从同样位于另一个 jar 中的 jar 访问类和 API
- python - ValueError: Input signal length=2 is too small to resample from 44100->16000
- python - Python:我必须四舍五入才能让它工作
- python - 使用 Clock.schedule_interval 和套接字时,kivy 应用程序崩溃