Reputation: 49
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
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