I'm not sure why I'm not getting any data returned back. I know the API key and URL is working properly. Below is the Struct and my class I'm using. I also included what I'm doing in my SwiftUI file.
In the response I can see that I am getting back a 200. I've tried a few different ways to mapping the data to my view, but so far no luck.
// MARK: - Welcome
struct WeatherDataModel: Codable, Identifiable {
let id = UUID()
let lat, lon: Double
let timezone: String
let current: Current
let daily: [Daily]
enum CodingKeys: String, CodingKey {
case lat, lon, timezone
case current, daily
}
}
// MARK: - Current
struct Current: Codable {
let dt, sunrise, sunset: Int
let temp, feelsLike: Double
let pressure, humidity: Int
let dewPoint: Double
let uvi, clouds, visibility: Int
let windSpeed: Double
let windDeg: Int
let weather: [Weather]
enum CodingKeys: String, CodingKey {
case dt, sunrise, sunset, temp
case feelsLike = "feels_like"
case pressure, humidity
case dewPoint = "dew_point"
case uvi, clouds, visibility
case windSpeed = "wind_speed"
case windDeg = "wind_deg"
case weather
}
}
// MARK: - Weather
struct Weather: Codable {
let id: Int
let main, weatherDescription, icon: String
enum CodingKeys: String, CodingKey {
case id, main
case weatherDescription = "description"
case icon
}
}
// MARK: - Daily
struct Daily: Codable {
let dt, sunrise, sunset, moonrise: Int
let moonset: Int
let moonPhase: Double
let temp: Temp
let feelsLike: FeelsLike
let pressure, humidity: Int
let dewPoint, windSpeed: Double
let windDeg: Int
let windGust: Double
let weather: [Weather]
let clouds: Int
let pop: Double
let rain: Double?
let uvi: Double
enum CodingKeys: String, CodingKey {
case dt, sunrise, sunset, moonrise, moonset
case moonPhase = "moon_phase"
case temp
case feelsLike = "feels_like"
case pressure, humidity
case dewPoint = "dew_point"
case windSpeed = "wind_speed"
case windDeg = "wind_deg"
case windGust = "wind_gust"
case weather, clouds, pop, rain, uvi
}
}
// MARK: - FeelsLike
struct FeelsLike: Codable {
let day, night, eve, morn: Double
}
// MARK: - Temp
struct Temp: Codable {
let day, min, max, night: Double
let eve, morn: Double
}
typealias weatherData = [WeatherDataModel]
class DownloadWeatherData: ObservableObject {
@Published var weatherdata: [WeatherDataModel] = []
var weatherCancellabes = Set<AnyCancellable>()
init() {
print("loading weather init")
getWeather(weatherUrl: "<my url>")
}
func getWeather(weatherUrl: String) {
guard let weatherUrl = URL(string: weatherUrl) else { return }
URLSession.shared.dataTaskPublisher(for: weatherUrl)
.subscribe(on: DispatchQueue.global(qos: .background))
.receive(on: DispatchQueue.main)
.tryMap { (data, response) -> Data in
print(response)
guard
let response = response as? HTTPURLResponse,
response.statusCode >= 200 && response.statusCode < 300 else {
throw URLError(.badServerResponse)
}
print("data \(data)")
return data
}
.decode(type: [WeatherDataModel].self, decoder: JSONDecoder())
.sink { (completion) in
} receiveValue: { [weak self] (returnedWeatherData) in
self?.weatherdata = returnedWeatherData
print("returnedWeatherData \(returnedWeatherData)")
}
.store(in: &weatherCancellabes)
}
}
struct WeatherView: View {
@StateObject var weatherData = DownloadWeatherData()
var body: some View {
VStack {
ForEach(weatherData.weatherdata) { day in
Text(day.timezone)
}
}
}
}
The error I'm getting here is No exact matches in call to initializer
Tips:
.keyDecodingStrategy = .convertFromSnakeCase
for your JSON decoder; all underbar key, like wind_gust
, will be automatically convert to camelCase, windGust
for example.let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
Use optional instead of non-optional model's properties to make sure any missing return keys will not fail your decoder. If the property is 100% guarantee from your backend dev, you can remove optional later.
Check datatype carefully of the response string from server, sometimes they return String
but we use model with Double
or Int
property and also check Array
or Dictionary
; as my experience, most of time the root object is Dictionary
so just check [WeatherDataModel]
again.