SwiftUI 解码 JSON 数据并显示在列表中 - 解码错误

SwiftUI decode JSON data and show in a list - Decode error

我正在使用 SwiftUI 构建一个简单的天气应用程序并打开天气地图 APIs。为了显示天气预报,我使用了下面的 API 调用。

    func getForecastWeather() async throws -> ForecastResponseBody {
        guard let url = URL(string: "https://api.openweathermap.org/data/2.5/forecast?lat=35&lon=139&appid=api-key") else {fatalError("Missing URL")}

        let urlRequest = URLRequest(url: url)

        let (data, response) = try await URLSession.shared.data(for: urlRequest)

        guard (response as? HTTPURLResponse)?.statusCode == 200 else { fatalError("Error fetching weather data")}

        let decodedData = try JSONDecoder().decode(ForecastResponseBody.self, from: data)

        print(decodedData)

        return decodedData
    }

JSON模型是这样的

import Foundation

struct ResponseBodyByForecast: Decodable {
    var cod: String
    var message: Double
    var list: [forecastList]
    
    
    struct forecastList: Decodable {
        var main: ForecastMainResponse
        var weather: ForecastWeatherResponse
        var clouds: ForecastCloudResponse
        var dt_txt: String
    }
    
    struct ForecastMainResponse:Decodable{
        var temp_min: Double
        var temp_max: Double
        var humidity: Double
        var pressure: Double
    }
    
    struct ForecastWeatherResponse:Decodable{
        var id: Double
        var main: String
        var description: String
        
    }
    
    struct ForecastCloudResponse:Decodable{
        var all: Double
    }
    
}

而实际的 JSON 响应是

      

{
  "cod": "200",
  "message": 0,
  "cnt": 40,
  "list": [
    {
      "dt": 1647345600,
      "main": {
        "temp": 286.88,
        "feels_like": 285.93,
        "temp_min": 286.74,
        "temp_max": 286.88,
        "pressure": 1021,
        "sea_level": 1021,
        "grnd_level": 1018,
        "humidity": 62,
        "temp_kf": 0.14
      },
      "weather": [
        {
          "id": 804,
          "main": "Clouds",
          "description": "overcast clouds",
          "icon": "04d"
        }
      ],
      "clouds": {
        "all": 85
      },
      "wind": {
        "speed": 3.25,
        "deg": 134,
        "gust": 4.45
      },
      "visibility": 10000,
      "pop": 0,
      "sys": {
        "pod": "d"
      },
      "dt_txt": "2022-03-15 12:00:00"
    },
    {
      "dt": 1647356400,
      "main": {
        "temp": 286.71,
        "feels_like": 285.77,
        "temp_min": 286.38,
        "temp_max": 286.71,
        "pressure": 1021,
        "sea_level": 1021,
        "grnd_level": 1017,
        "humidity": 63,
        "temp_kf": 0.33
      },
      "weather": [
        {
          "id": 804,
          "main": "Clouds",
          "description": "overcast clouds",
          "icon": "04d"
        }
      ],
      "clouds": {
        "all": 90
      },
      "wind": {
        "speed": 3.34,
        "deg": 172,
        "gust": 4.03
      },
      "visibility": 10000,
      "pop": 0,
      "sys": {
        "pod": "d"
      },
      "dt_txt": "2022-03-15 15:00:00"
    },

    ...

 ],
  "city": {
    "id": 2643743,
    "name": "London",
    "coord": {
      "lat": 51.5073,
      "lon": -0.1277
    },
    "country": "GB",
    "population": 1000000,
    "timezone": 0,
    "sunrise": 1647324903,
    "sunset": 1647367441
  }
}

我在访问解码数据时遇到错误。我可以看到 API 响应,它是通过 API 调用函数打印的。但是无法访问数据。这就是我尝试访问数据的方式,

import SwiftUI

struct ForecastView: View {
    var weatherManager = WeatherManager()
    @State var weather: ForecastResponseBody?
    var body: some View {
        Text("Test")
        
            .onAppear {
                
                Task {
                    do {
                        weather = try await weatherManager.getForecastWeather()
                        print("Weather" , weather)
                        
                    } catch {
                        print("Error occured while fetching your weather results: \(error)")
                    }
                }
                
            }
    }
}

struct ForecastView_Previews: PreviewProvider {
    static var previews: some View {
        ForecastView()
    }
}

我得到 Swift.DecodingError。

完整的错误代码:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "list", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "weather", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

非常感谢您的帮助。

问题是您的 JSON 数据包含天气数组,但您的模型中只有一个对象。参见

 "weather": [
        {
          "id": 804,
          "main": "Clouds",
          "description": "overcast clouds",
          "icon": "04d"
        }
      ],

方括号表示这是一个数组。但是在您的模型中,您将其映射到字典中。 解决方案是从 JSON 文件中删除这些括号,或者将模型中的天气设置为这样

var weather: [ForecastWeatherResponse]