I'm currently working on an application that displays the weather using the OpenWeatherMap OneCall API but I am struggling to figure out how to display the data. When I try to display it in a list the result is just a blank list with no error messages or anything.
Here are my Weather structs:
import Foundation
struct Weather: Codable {
var lat: Double
var lon: Double
var timezone: String
var timezone_offset: Int
var current: Current
var hourly: [Hourly]
var daily: [Daily]
}
struct Current: Codable {
var dt: Int
var sunrise: Int
var sunset: Int
var temp: Double
var feels_like: Double
var pressure: Int
var humidity: Int
var dew_point: Double
var uvi: Double
var clouds: Int
var visibility: Int
var wind_speed: Double
var wind_deg: Int
var weather: [WeatherData]
var rain: Double
}
struct WeatherData: Codable {
var id: Int
var main: String
var description: String
var icon: String
}
struct Hourly: Codable, Identifiable {
var id = UUID()
var dt: Int
var temp: Double
var feels_like: Double
var pressure: Int
var humidity: Int
var dew_point: Double
var clouds: Int
var wind_speed: Double
var wind_deg: Int
var weather: [WeatherData]
var rain: Double
}
struct Daily: Codable {
var dt: Int
var sunrise: Int
var sunset: Int
var temp: TempDetail
var feels_like: FeelsLikeDetail
var pressure: Int
var humidity: Int
var dew_point: Double
var wind_speed: Double
var wind_deg: Double
var weather: [WeatherData]
var clouds: Int
var rain: Double
}
struct TempDetail: Codable {
var day: Double
var min: Double
var max: Double
var night: Double
var eve: Double
var morn: Double
}
struct FeelsLikeDetail: Codable {
var day: Double
var night: Double
var eve: Double
var morn: Double
}
And here is my attempt at an API Request and JSON Decoding:
import SwiftUI
struct ContentView: View {
@State var hourly = [Hourly]()
func loadData() {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/onecall?lat=40.7128&lon=74.0060&units=metric&appid=e69debdf0100132e2076aae6d1c80a2b") else {
print("Invalid URL")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let decodedResponse = try? JSONDecoder().decode(Weather.self, from: data) {
DispatchQueue.main.async {
self.hourly = decodedResponse.hourly
}
return
}
}
print("Fetch Failed: \(error?.localizedDescription ?? "Unknown Error")")
}.resume()
}
var body: some View {
List(hourly) { item in
Text("\(item.temp)")
}.onAppear(perform: loadData)
}
}
struct WeatherAPI_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The question is not particularly related to SwiftUI.
The main issue is that you have to specify CodingKeys if you add a struct member which must not be decoded ( id
in Hourly).
Another issue is that rain
is optional in Daily
and Hourly
and is a dictionary in Hourly
.
It's highly recommended to handle any error and print the actual error
instance. You should get
keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "hourly", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "id", intValue: nil) ("id").", underlyingError: nil))
And the URLRequest
is not needed
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error { print(error); return }
do {
let decodedResponse = try JSONDecoder().decode(Weather.self, from: data!)
DispatchQueue.main.async {
self.hourly = decodedResponse.hourly
}
} catch { print(error) }
}.resume()
Note: There is no reason to declare all struct members as variables. Declare them as constants ( let
)
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.