【问题标题】:OpenWeather data not returning using SwiftUI and CombineOpenWeather 数据未使用 SwiftUI 和 Combine 返回
【发布时间】:2021-11-06 13:47:01
【问题描述】:

我不确定为什么没有返回任何数据。我知道 API 密钥和 URL 工作正常。下面是我正在使用的 Struct 和我的类。我还在我的 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

【问题讨论】:

  • “对初始化程序的调用没有完全匹配”——在哪一行?
  • 你可能想看看 github 上的这项工作:github.com/workingDog/OWOneCall 一些数据结构可能相似。

标签: swiftui combine


【解决方案1】:

提示:

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

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

【讨论】:

  • 谢谢@Kawa。我回去看了看回复,我回来了{ }而不是[ ]
猜你喜欢
  • 2021-01-16
  • 2021-06-16
  • 1970-01-01
  • 2020-06-10
  • 2018-10-18
  • 1970-01-01
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
相关资源
最近更新 更多