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]
我正在使用 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]