Swift UIKit应用JSON解码失败求助:所有属性均为nil
OpenWeatherMap JSON解码后所有属性为nil的问题排查与解决
问题描述
在UIKit应用中调用OpenWeatherMap API获取天气数据,解码返回的JSON后,Response实例的所有属性均为nil,但直接访问API链接可获取正确的JSON数据。
解码代码
override func viewDidLoad() { super.viewDidLoad() cidadelabel.text = city! downloadJSON { print("success") } print(result.main?.temp!) // var temperatura = result?.main?.temp // temperatura = temperatura! - 273.15 // temperatureLabel.text = "\(String(temperatura!))°C" } func downloadJSON(completed: @escaping () -> ()){ let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?appid=******d&q=" + city!) URLSession.shared.dataTask(with: url!) { data, response, error in if error == nil{ do{ print(data!) print(response!) self.result = try JSONDecoder().decode(Response.self, from: data!) DispatchQueue.main.async { completed() } } catch { print("error fetching data from the api") print(String(describing: error)) } } }.resume() }
原JSON接收结构体
import Foundation struct Response: Codable { var coord: Coord? var weather: [WeatherBase]? var main: Main? var visibility: Int? var wind: Wind? var rain: Rain? var clouds: Clouds? var dt: Int? var sys: Sys? var timezone: Int? var id: Int? var name: String? var cod: Int? } struct Coord: Codable { var lon: Double? var lat: Double? } struct WeatherBase: Codable { var id: String { _id! } private var _id: String? var base: String? mutating func prepare() { _id = _id ?? UUID().uuidString } } struct Weather: Codable { var id: Int? var main: String? var description: String? var icon: String? } struct Main: Codable { var temp: Double? var feels_like: Double? var temp_min: Double? var temp_max: Double? var pressure: Int? var humidity: Int? } struct Wind: Codable { var speed: Double? var deg: Int? } struct Rain: Codable{ var umh: Int? } struct Clouds: Codable { var all: Int? } struct Sys: Codable { var type: Int? var id: Int? var country: String? var sunrise: Int? var sunset: Int? }
API返回的JSON
{"coord":{"lon":-35.7353,"lat":-9.6658},"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02d"}],"base":"stations","main":{"temp":302.84,"feels_like":305.59,"temp_min":302.84,"temp_max":302.84,"pressure":1011,"humidity":61},"visibility":10000,"wind":{"speed":7.2,"deg":90},"clouds":{"all":20},"dt":1672689129,"sys":{"type":1,"id":8413,"country":"BR","sunrise":1672646788,"sunset":1672692412},"timezone":-10800,"id":3395981,"name":"Maceió","cod":200}
问题现象
解码后得到的Response实例所有属性均为nil:
Response(coord: nil, weather: nil, main: nil, visibility: nil, wind: nil, rain: nil, clouds: nil, dt: nil, sys: nil, timezone: nil, id: nil, name: nil, cod: nil)
解决步骤
1. 修正结构体类型匹配错误
- Response中的
weather字段声明为[WeatherBase]?,但API返回的是符合Weather结构体的数组,将其改为[Weather]?,并删除无用的WeatherBase结构体。 - Rain结构体的字段名错误:OpenWeatherMap的rain字段为
1h或3h,而非umh,当前返回中无rain数据,可暂时保留可选类型或修正字段名。
修正后的核心结构体:
struct Response: Codable { var coord: Coord? var weather: [Weather]? var main: Main? var visibility: Int? var wind: Wind? var rain: Rain? var clouds: Clouds? var dt: Int? var sys: Sys? var timezone: Int? var id: Int? var name: String? var cod: Int? } // 保留正确的Weather结构体,删除WeatherBase struct Weather: Codable { var id: Int? var main: String? var description: String? var icon: String? } // 修正Rain结构体(如需处理降雨数据) struct Rain: Codable{ enum CodingKeys: String, CodingKey { case oneHour = "1h" } var oneHour: Double? }
2. 调整解码后逻辑的执行时机
viewDidLoad中直接调用print(result.main?.temp!)是在异步请求完成前执行的,此时result尚未被赋值,需将所有依赖result的逻辑放到completed闭包内:
override func viewDidLoad() { super.viewDidLoad() cidadelabel.text = city! downloadJSON { print("success") // 此处访问result才是有效的 if let temp = self.result.main?.temp { let temperatura = temp - 273.15 self.temperatureLabel.text = String(format: "%.1f°C", temperatura) } } }
3. 避免强制解包
代码中大量使用!强制解包,容易导致崩溃,建议使用可选绑定处理可选值:
// 安全创建URL guard let cityName = city, let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?appid=******d&q=" + cityName) else { print("无效的城市名或URL") return }
4. 查看精准解码错误
修改catch块的打印逻辑,获取更详细的解码错误信息,便于定位问题:
catch { print("JSON解码失败:\(error)") if let decodingError = error as? DecodingError { print("解码错误详情:\(decodingError.localizedDescription)") } }
内容的提问来源于stack exchange,提问作者Caio
相关产品推荐
相关产品推荐

