Search code examples
iosjsonswiftjson-serialization

Parsing nested JSON in Swift compared with Objective-C


I am trying to parse some JSON in Swift that I was previously parsing in Objective-C and am having some difficulties.

In objective-C I was able to parse it simply enough using:

NSError* error;
NSDictionary *jsonResults = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSNumber *temp = jsonResults[@"main"][@"temp"];
NSNumber *humidity = jsonResults[@"main"][@"humidity"];

In Swift, my code so far is giving errors when I try to serialize into a dictionary or, alternatively, if I serialize intoa string when I try to access the values in the JSON.

What is the proper way to do this in Swift. Here is version where I try to to serialize into Dictionary and it gives an error

  //assemble url query items
    components.queryItems = queryItems
    let url = components.url
    let task = URLSession.shared.dataTask(with: url!) { //open 2
    [weak self] data, response, error in
    print("heard back from task")
    guard let data = data, error == nil else { return }
    do {
    let jsonResults = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [Dictionary:Any]
    //Gives error Dictionary' requires that 'Value' conform to 'Hashable'
    let main = jsonResults["main"] as Any
    let temp = main[3]
    completion("got here")
    } catch let error as NSError {
    print(error)
    }

Here is a sample of the JSON:

{"coord":{"lon":10.73,"lat":59.91},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"base":"stations","main":{"temp":49.62,"feels_like":43.45,"temp_min":48,"temp_max":52,"pressure":987,"humidity":30},"wind":{"speed":1.99,"deg":95,"gust":7},"clouds":{"all":95},"dt":1589387530,"sys":{"type":3,"id":2009047,"country":"NO","sunrise":1589337830,"sunset":1589398989},"timezone":7200,"id":3143242,"name":"Oslo County","cod":200}

Solution

  • In swift you only need the below code: -

    Model:

    struct Model: Codable {
        let coord: Coord
        let weather: [Weather]
        let base: String
        let main: Main
        let wind: Wind
        let clouds: Clouds
        let dt: Int
        let sys: Sys
        let timezone, id: Int
        let name: String
        let cod: Int
    }
    
    struct Clouds: Codable {
        let all: Int
    }
    
    struct Coord: Codable {
        let lon, lat: Double
    }
    
    struct Main: Codable {
        let temp, feelsLike: Double
        let tempMin, tempMax, pressure, humidity: Int
    
        enum CodingKeys: String, CodingKey {
            case temp
            case feelsLike = "feels_like"
            case tempMin = "temp_min"
            case tempMax = "temp_max"
            case pressure, humidity
        }
    }
    
    struct Sys: Codable {
        let type, id: Int
        let country: String
        let sunrise, sunset: Int
    }
    
    struct Weather: Codable {
        let id: Int
        let main, description, icon: String
    }
    
    struct Wind: Codable {
        let speed: Double
        let deg, gust: Int
    }
    

    Parsing:

    do {
        let model = try JSONDecoder().decode(Model.self, from: data)
    } catch {
        print(error.localizedDescription)
    }