我正在尝试解码一些 JSON 数据,但遇到了 CodingKeys 问题。我能够毫无问题地解码整个 JSON,直到我添加带有编码键的枚举。
工作代码如下所示
import Foundation
// Top-level response struct
struct WeatherData: Codable {
let weather: [Weather]
let main: MainWeather
let visibility: Double
let wind: Wind
let clouds: Clouds
let sys: System
let name: String
}
// Weather condition struct (array)
struct Weather: Codable {
let id: Int
let main: String
let description: String
}
// Main weather data struct
struct MainWeather: Codable {
let temp: Double
let pressure: Int
let humidity: Double
}
// Wind data struct
struct Wind: Codable {
let speed: Double
let deg: Int
}
struct Clouds: Codable {
let all: Double
}
// System data struct
struct System: Codable {
let sunrise: TimeInterval
let sunset: TimeInterval
}
当我将代码更改为这样时,它会停止解码
import Foundation
// Top-level response struct
struct WeatherData: Codable {
let weather: [Weather]
let main: MainWeather
let visibility: Double
let wind: Wind
let clouds: Clouds
let sys: System
let name: String
}
// Weather condition struct (array)
struct Weather: Codable {
let id: Int
let main: String
let description: String
}
// Main weather data struct
struct MainWeather: Codable {
let temp: Double
let pressure: Int
let humidity: Double
let tempMin: Double
let tempMax: Double
let feelsLike: Double
let seaLevel: Double
let grndLevel: Double
// Custom coding keys to map JSON keys with underscores
enum CodingKeys: String, CodingKey {
case temp
case feelsLike = "feels_like"
case tempMin = "temp_min"
case tempMax = "temp_max"
case pressure
case humidity
case seaLevel = "sea_level"
case grndLevel = "grnd_level"
}
}
// Wind data struct
struct Wind: Codable {
let speed: Double
let deg: Int
}
struct Clouds: Codable {
let all: Double
}
// System data struct
struct System: Codable {
let sunrise: TimeInterval
let sunset: TimeInterval
}
我的解码代码如下
private let baseURL = URL(string: "https://api.openweathermap.org/data/2.5/weather")!
func fetchWeather(for location: String) async throws -> WeatherData {
var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)!
components.queryItems = [
URLQueryItem(name: "q", value: location.lowercased()),
URLQueryItem(name: "appid", value: Constants.apiKey),
URLQueryItem(name: "units", value: "metric")
]
guard let fetchURL = components.url else {
throw FetchError.invalidURL
}
let (data, response) = try await URLSession.shared.data(from: fetchURL)
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
throw FetchError.badResponse
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let weather = try decoder.decode(WeatherData.self, from: data)
return weather
}
最后,JSON 数据如下所示
{
"coord": {
"lon": 13.3776,
"lat": 49.7475
},
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04n"
}
],
"base": "stations",
"main": {
"temp": 283.88,
"feels_like": 283.38,
"temp_min": 282.31,
"temp_max": 285.3,
"pressure": 1025,
"humidity": 91,
"sea_level": 1025,
"grnd_level": 979
},
"visibility": 10000,
"wind": {
"speed": 0.89,
"deg": 245,
"gust": 2.24
},
"clouds": {
"all": 100
},
"dt": 1729444238,
"sys": {
"type": 2,
"id": 20633,
"country": "CZ",
"sunrise": 1729402572,
"sunset": 1729440356
},
"timezone": 7200,
"id": 3068160,
"name": "Pilsen",
"cod": 200
}
在我看来,您正在“双重修复”您的密钥转换。将您的
keyDecodingStrategy
设置为 .convertFromSnakeCase
或 提供 CodingKeys
将您的属性名称映射到其键,但 不能两者兼而有之。