I am trying to decode a JSON with the help of codable - https://pastebin.com/Xfjj2XiP
However I'm getting this error when I do so.
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "txt_forecast", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
Here's the code I'm using:
struct container: Decodable {
var days: [forecastDay]
//Coding keys
enum CodingKeys: String, CodingKey {
case forecast = "forecast"
case txt_forecast = "txt_forecast"
case forecastday = "forecastday"
}
// Decoding
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let forecast = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .forecast)
let txt_forecast = try forecast.nestedContainer(keyedBy: CodingKeys.self, forKey: .txt_forecast)
let forecastdays = try txt_forecast.nestedContainer(keyedBy: CodingKeys.self, forKey: .forecastday)
let forecastdaysData = try forecastdays.decode(String.self, forKey: .forecastday)
days = try JSONDecoder().decode([forecastDay].self, from: forecastdaysData.data(using: .utf8)!)
print(days)
}
}
struct forecastDay: Decodable {
var period: Int?
var icon: String?
var title: String?
var fcttext: String?
//Coding keys
enum CodingKeys: String, CodingKey {
case period = "period"
case icon = "icon"
case title = "title"
case fcttext = "fcttext"
}
// Decoding
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
period = try container.decode(Int.self, forKey: .period)
icon = try container.decode(String.self, forKey: .icon)
title = try container.decode(String.self, forKey: .title)
fcttext = try container.decode(String.self, forKey: .fcttext)
}
}
The variable names in forecastDay
do not differ from the keys in the JSON and init(from decoder:)
does nothing custom either, so the struct for a forecast day period can be simplified.
struct ForecastDayPeriod: Decodable {
let period: Int
let icon: String
let title: String
let fcttext: String
}
Now it's best to use an enum with key(s) for each level in the JSON. Also, init(from decoder:)
should not create a new JSONDecoder
.
struct ForecastDay: Decodable {
let periods: [ForecastDayPeriod]
enum CodingKeys: String, CodingKey {
case forecast
}
enum ForecastKeys: String, CodingKey {
case txtForecast = "txt_forecast"
}
enum TxtForecastKeys: String, CodingKey {
case forecastday
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let forecast = try values.nestedContainer(keyedBy: ForecastKeys.self,
forKey: .forecast)
let txtForecast = try forecast.nestedContainer(keyedBy: TxtForecastKeys.self,
forKey: .txtForecast)
periods = try txtForecast.decode([ForecastDayPeriod].self,
forKey: .forecastday)
}
}
Now it should be possible to decode the JSON from the pastebin example.
do {
let jsonData: Data = ...
let forecastDay = try JSONDecoder().decode(ForecastDay.self, from: jsonData)
} catch {
print("Error: \(error)")
}
来源:https://stackoverflow.com/questions/50439824/codable-error-expected-to-decode-dictionarystring-any-but-found-an-array-in