Trying to parse nested json that contains a element named ‘weather’. I run into errors with in the line: try decoder.decode(WeatherClass.Top.self, it errors out.
However if I remove the weather element from struct definition then it works. Don’t know how to figure out the struct construct and code for parsing nested json
JSON Listing:
{"lat":39.9295,"lon":-85.608,"timezone":"America/Chicago","timezone_offset":-18000,"current":{"dt":1690514755,"sunrise":1690457901,"sunset":1690507157,"temp":302.6,"feels_like":306.89,"pressure":1015,"humidity":70,"dew_point":296.55,"uvi":0,"clouds":0,"visibility":10000,"wind_speed":1.54,"wind_deg":0,"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}]}}
Struct definition:
struct Top : Codable {
let lat: Double
let lon: Double
let timezone: String?
let timezone_offset: Double
let current: CurrentJSON?
enum CodingKeys : String, CodingKey {
case lat = "lat"
case lon = "lon"
case timezone = "timezone"
case timezone_offset = "timezone_offset"
case current = "current"
}
}
struct CurrentJSON: Codable {
let dt:Int //convert to date time
let sunrise:Int
let sunset:Int
let temp:Double
let feels_like:Double
let pressure: Int
let humidity: Int
let dew_point: Double
let uvi:Double
let clouds: Int
let visibility:Int
let wind_speed: Double
let wind_deg: Int
let weather: WeatherJSON?
enum CodingKeys : String, CodingKey {
case dt = "dt"
case sunrise = "sunrise"
case sunset = "sunset"
case temp = "temp"
case feels_like = "feels_like"
case pressure = "pressure"
case humidity = "humidity"
case dew_point = "dew_point"
case uvi = "uvi"
case clouds = "clouds"
case visibility = "visibility"
case wind_speed = "wind_speed"
case wind_deg = "wind_deg"
case weather = "weather"
}
}
struct WeatherJSON: Codable {
let id: String?
let main: String?
let description: String?
let icon: String?
enum CodingKeys : String, CodingKey {
case id = "id"
case main = "main"
case description = "description"
case icon = "icon"
}
}
Code Listing:
func getWeatherCurrentDay(url: URL,
latitudeStr: String,
longitudeStr: String,
completion: @escaping (Bool, currentWeather) -> () ){
let dataTask = URLSession.shared.dataTask(with:url!) { [self] responseData, response, error in
do {
if let data = responseData {
// let _ = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
self.jsonString = String(data: data, encoding: .utf8)!
print("JSON String:(String(describing: self.jsonString))")
if self.jsonString != nil {
try DispatchQueue.main.sync { [unowned self] in
let decoder = JSONDecoder()
let jsonData = try decoder.decode(Top.self, from: data
// parse data here
}
}
}
} catch {
print("error")
}
}
}
2
Answers
The weather field is an array of objects in the JSON response but in your CurrentJSON struct weather is defined as a single instance. Additionally, the weather id field in the JSON response is being returned as an int but you are decoding it as a string
The correct models would look like:
In the "struct WeatherJSON", "id" is actually Int, not String.
That is why it is failing.