使用 SwiftUI 和 Combine 不返回 OpenWeather 数据

OpenWeather data not returning using SwiftUI and Combine

我不确定为什么没有返回任何数据。我知道 API 键和 URL 键工作正常。下面是结构和我正在使用的 class。我还在我的 SwiftUI 文件中包含了我正在做的事情。

在响应中我可以看到我返回了 200。我尝试了几种不同的方法来将数据映射到我的视图,但到目前为止没有成功。

// 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)
            }
        }
    }
}

我得到的错误是No exact matches in call to initializer

提示:

  1. 您不需要定义 CodingKeys 枚举,只需为您的 JSON 解码器设置 .keyDecodingStrategy = .convertFromSnakeCase;所有下划线键,如 wind_gust,将自动转换为驼峰式,例如 windGust
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
  1. 使用可选而不是非可选模型的属性来确保任何丢失的 return 键不会使您的解码器失败。如果 属性 是后端开发人员 100% 的保证,您可以稍后删除可选的。

  2. 仔细检查来自服务器的响应字符串的数据类型,有时它们 return String 但我们使用模型 DoubleInt 属性 并检查 ArrayDictionary;根据我的经验,大多数时候根对象是 Dictionary 所以只需再次检查 [WeatherDataModel]