E.YILDIRIM
E.YILDIRIM

Reputation: 49

The JSON data couldn’t be read because it isn’t in the correct format

I want to take weather information with JSON but there is an error:

The data couldn’t be read because it isn’t in the correct format.

override func viewDidLoad() {
            super.viewDidLoad()
            let url = "https://api.openweathermap.org/data/2.5/weather?q=bursa,tr&appid=00f63a1cff271776651468c0204c422c"
            getData(from: url)
        }
        
        private func getData (from url : String){
           let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { data , response , error in
                guard let data = data ,  error == nil else {
                    print ("birşeyler ters gitti")
                    return
                }
            var main : Response?
                do {
                    main = try JSONDecoder().decode(Response.self , from: data)
                } catch{
                    print ("ERROR IS HERE!!! \(error.localizedDescription)")
                }
                guard let json = main else {
                    return
                }
            print (json.weather)
                })
            task.resume()
        
        
        
    }}
        
    struct Response : Codable {
               let weather : myResult
               let status : String
               
           }
    struct myResult : Codable {
               let main : String
               let description : String
               let icon : String
           }

API Response is like that :

{"coord": { "lon": 139,"lat": 35},
  "weather": [
    {
      "id": 800,
      "main": "Clear",
      "description": "clear sky",
      "icon": "01n"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 281.52,
    "feels_like": 278.99,
    "temp_min": 280.15,
    "temp_max": 283.71,
    "pressure": 1016,
    "humidity": 93
  },
  "wind": {
    "speed": 0.47,
    "deg": 107.538
  },
  "clouds": {
    "all": 2
  },
  "dt": 1560350192,
  "sys": {
    "type": 3,
    "id": 2019346,
    "message": 0.0065,
    "country": "JP",
    "sunrise": 1560281377,
    "sunset": 1560333478
  },
  "timezone": 32400,
  "id": 1851632,
  "name": "Shuzenji",
  "cod": 200
}

Upvotes: 2

Views: 1732

Answers (1)

pawello2222
pawello2222

Reputation: 54426

First, error.localizedDescription is meant to display an information for the user. It's not useful for debugging. If you replace it with error:

} catch {
    print ("ERROR IS HERE!!! \(error)") // <- remove .localizedDescription
}

you will get more details:

ERROR IS HERE!!! typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "weather", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

To solve this you need to declare weather as an array:

let weather: [myResult]

I'd also recommend replacing myResult with Weather (or at least capitalised MyResult) as it will be more readable:

struct Weather: Codable {
    let main: String
    let description: String
    let icon: String
}

Also, in the JSON response you provided there is no status field so you may need to remove it from the Response class (or make it optional).

If you'd like to add more fields to the response, declare them according to your JSON structure. Eg. if you want to add humidity and temperature you can do:

struct Response: Codable {
    ...
    let main: Main
}

struct Main: Codable {
    let temp: Double
    let humidity: Double
}

To have a more readable code you can use CodingKeys - then your variable names can be independent from JSON variables.

struct Main: Codable {
    enum CodingKeys: String, CodingKey {
        case temperature = "temp"
        case humidity
    }
    
    let temperature: Double
    let humidity: Double
}

Summing up, your Response may look like this:

struct Response: Codable {
    let weather: [Weather]
    let main: Main
    // alternatively declare `status` optional
    // let status: String?
}

struct Weather: Codable {
    let main: String
    let description: String
    let icon: String
}

struct Main: Codable {
    enum CodingKeys: String, CodingKey {
        case temperature = "temp"
        case humidity
    }
    
    let temperature: Double
    let humidity: Double
}

Upvotes: 1

Related Questions