skip to Main Content

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


  1. 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:

    struct WeatherJSON: Codable {
        let id: Int
        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"
        }
    }
    
    struct CurrentJSON: Codable {
        let dt: Int
        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 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"
        }
    }
    
    Login or Signup to reply.
  2. In the "struct WeatherJSON", "id" is actually Int, not String.

    That is why it is failing.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search