Swift中如何将含weather数组的JSON转为Codable?
正确解析天气JSON的Swift Codable实现方案
问题根源分析
你遇到的解析失败主要有几个核心原因:
- 误解了
weather字段的结构:它是包含单个对象的数组,而非带[0]键的字典,直接用[Weather]类型即可正确映射。 - 冗余的
WeatherBase结构体完全多余,且和JSON结构不匹配,反而干扰解析逻辑。 description是Swift关键字,直接作为Codable属性会导致编译或解析异常,需要通过编码键做映射。Rain结构体字段定义错误:当前示例JSON中无rain字段,即使后续接口返回,常见字段也是1h/3h而非umh。
修正后的完整代码
import Foundation struct WeatherResponse: Codable { let coord: Coord let weather: [Weather] let base: String let main: Main let visibility: Int let wind: Wind let clouds: Clouds let dt: Int let sys: Sys let timezone: Int let id: Int let name: String let cod: Int // 若后续接口可能返回rain字段,按实际结构定义(可选) let rain: Rain? } struct Coord: Codable { let lon: Double let lat: Double } struct Weather: Codable { let id: Int let main: String let description: String let icon: String // 处理Swift关键字description的映射 enum CodingKeys: String, CodingKey { case id, main, description, icon } } struct Main: Codable { let temp: Double let feelsLike: Double let tempMin: Double let tempMax: Double let pressure: Int let humidity: Int // 将JSON下划线命名转换为Swift驼峰命名(符合编码规范) enum CodingKeys: String, CodingKey { case temp case feelsLike = "feels_like" case tempMin = "temp_min" case tempMax = "temp_max" case pressure, humidity } } struct Wind: Codable { let speed: Double let deg: Int } // 按天气接口常见返回结构定义Rain字段 struct Rain: Codable { let oneHour: Double? enum CodingKeys: String, CodingKey { case oneHour = "1h" } } struct Clouds: Codable { let all: Int } struct Sys: Codable { let type: Int let id: Int let country: String let sunrise: Int let sunset: Int }
关键修改说明
- 移除冗余代码:删除完全无用的
WeatherBase结构体,避免逻辑混淆。 - 正确映射数组:
weather字段直接定义为[Weather],Codable会自动解析数组内的对象,无需手动处理索引。 - 关键字兼容:通过
CodingKeys保留description作为属性名,同时映射JSON中的同名字段,解决关键字冲突问题。 - 命名规范优化:将JSON的下划线命名转换为Swift风格的驼峰命名,提升代码可读性,同时通过编码键完成映射(可选但推荐)。
- 修正Rain结构:按照天气接口常见返回调整字段,设为可选类型,避免无rain字段时解析失败。
解析示例代码
// 假设已获取JSON对应的Data对象 func parseWeatherData(from data: Data) -> WeatherResponse? { do { let decoder = JSONDecoder() // 开启自动下划线转驼峰,配合Main结构体的编码键使用 decoder.keyDecodingStrategy = .convertFromSnakeCase let response = try decoder.decode(WeatherResponse.self, from: data) return response } catch { print("解析失败: \(error)") return nil } }
内容的提问来源于stack exchange,提问作者Caio
相关产品推荐
相关产品推荐

