I have used JSON structs before and managed to get them working with a different API, but this API's JSON data is slightly different, it seems to encompass the data in an array called 'List'. I assume it is the Structs below that are in the incorrect format? As when I run the app, I don't get any error messages, but the Label value that I am trying to change, does not change, nor does the value of 'Test' get printed to the console. I am trying to call the Description value and print it to a label.
JSON Structs below:
struct MyForecast : Decodable {
let cod : String
let message : Double
let cnt : Int
let list : [List]
let city : Cityy
let coordinate : Coordi
}
struct Coordi : Decodable {
let lat, lon : Double
}
struct Cityy : Decodable {
let id, population : Int
let name, country : String
let coord : Coordinate
}
struct Mainn : Decodable {
let temp, tempMin, tempMax : Double
let seaLevel, grndLevel, tempKf: Double
let pressure, humidity : Int
}
struct Windd : Decodable {
let speed : Double
let deg : Double
}
struct Weatherr : Decodable {
let id : Int
let icon : String
let main : MainEnum
let description: String
}
struct List : Decodable {
let dt : Date
let main : MainForecast
let weather : [Weatherr]
let clouds : Cloudss
let wind : Windd
let sys : Syss
let dtTxt : String
let rain: Rainn?
let city: Cityy
}
struct Syss : Decodable {
let pod: Pod
}
struct MainForecast : Decodable {
let temp, tempMin, tempMax, pressure, seaLevel, grndLevel, humidity, tempKf : Double?
}
struct Cloudss : Decodable {
let all : Int
}
struct Rainn: Codable {
let the3H: Double?
enum CodingKeys: String, CodingKey {
case the3H = "3h"
}
}
enum Pod: String, Codable {
case d = "d"
case n = "n"
}
enum MainEnum: String, Codable {
case clear = "Clear"
case clouds = "Clouds"
case rain = "Rain"
}
ViewController below:
class ForecastViewController: UIViewController {
@IBOutlet weak var testLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
guard let APIUrl = URL (string: "https://api.openweathermap.org/data/2.5/forecast?q=London&APPID=***APIKEY***&units=metric") else { return }
//API KEY
URLSession.shared.dataTask(with: APIUrl) { data, response, error in
guard let data = data else { return }
let decoderr = JSONDecoder()
do {
decoderr.keyDecodingStrategy = .convertFromSnakeCase
decoderr.dateDecodingStrategy = .secondsSince1970
let forecastData = try decoderr.decode(MyForecast.self, from: data)
if let test = forecastData.list.first?.city.name { //using .first because Weather is stored in an array
let description = test.description
print(description)
DispatchQueue.main.async {
self.testLabel.text! = description
}
}
else
{
print("weather not found")
}
} catch {
print(error.localizedDescription)
}
}.resume()
Your structs
are
were wrong before you edited the question.
The 5 day / 3 hour Forecast API of openweathermap.org
sends a different JSON structure as the Current Weather Data.
You can create the structs very easy yourself:
Data
quicktype.io creates the structs for you.
The forecast structs are (except Rain
there are no optionals at all )
struct MyForecast : Decodable {
let cod : String
let message : Double
let cnt : Int
let list : [List]
let city : City
}
struct Coordinate : Decodable {
let lat, lon : Double
}
struct City : Decodable {
let id, population : Int
let name, country : String
let coord : Coordinate
}
struct Main : Decodable {
let temp, tempMin, tempMax : Double
let seaLevel, grndLevel, tempKf: Double
let pressure, humidity : Int
}
struct Wind : Decodable {
let speed : Double
let deg : Double
}
struct Weather : Decodable {
let id : Int
let icon : String
let main : MainEnum
let description: String
}
struct List : Decodable {
let dt : Date
let main : MainForecast
let weather : [Weather]
let clouds : Clouds
let wind : Wind
let sys : Sys
let dtTxt : String
let rain: Rain?
}
struct Sys : Decodable {
let pod: Pod
}
struct MainForecast : Decodable {
let temp, tempMin, tempMax, pressure, seaLevel, grndLevel, humidity, tempKf : Double
}
struct Clouds : Decodable {
let all : Int
}
struct Rain: Codable {
let the3H: Double?
enum CodingKeys: String, CodingKey {
case the3H = "3h"
}
}
enum Pod: String, Codable {
case d, n
}
enum MainEnum: String, Codable {
case clear = "Clear"
case clouds = "Clouds"
case rain = "Rain"
}
To decode the structs you have to add date and key decoding strategies.
List
and Weather
are arrays
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .secondsSince1970
let forecastData = try decoder.decode(MyForecast.self, from: data)
if let test = forecastData.list.first?.weather.first? { //using .first because Weather is stored in an array
let description = test.description
print(description)
DispatchQueue.main.async {
self.testLabel.text! = description
}
} else { print("weather not found") }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.