You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift调用OpenWeather API获取温湿度数据返回nil如何解决?

问题排查与修复方案

核心错误点

  • API返回结构理解错误:OpenWeather /data/2.5/weather 接口的返回数据中,temp、humidity 属于根节点下的main字段,城市名称name属于根节点字段,你遍历的weather数组仅存储天气类型、图标等描述信息,不存在temp、humidity、name字段,强行从该数组取值自然全为nil。
  • 多余的重复解析逻辑:你已经用JSONDecoder解码了完整的返回数据,不需要再手动遍历weather数组重新赋值,额外的赋值操作反而把正确解析出来的数值覆盖成了nil。
  • 不必要的请求头配置:OpenWeather的公开接口不需要配置Authorization请求头,你已经在URL参数中携带了appid,额外加的Bearer头可能导致接口鉴权异常。
  • Codable结构体定义偏差:name字段不在main节点下,你当前的结构体定义无法正确解析到城市名称。
  • 强制解包风险:代码中多处使用!强制解包可选值,一旦接口返回异常会直接触发崩溃。

修复后代码

第一步:修正Codable结构体定义

// 对应接口返回根节点
struct WeatherResponse: Codable {
    let main: Weather
    let name: String?
}

// 对应main节点的温湿度数据
struct Weather: Codable {
    var temp: Double?
    var humidity: Int?
}

第二步:重写fetchWeather方法

func fetchWeather(lat: Double, lon: Double, completionHandler: @escaping (Weather?, String?, Error?) -> Void) {
    let apikey = "替换为你的真实OpenWeather APIKey"
    // URL添加units=metric参数可直接返回摄氏度单位的温度,默认返回开尔文温度
    guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?lat=\(lat)&lon=\(lon)&appid=\(apikey)&units=metric") else {
        completionHandler(nil, nil, NSError(domain: "InvalidURL", code: -1))
        return
    }
    // 不需要额外配置请求头
    URLSession.shared.dataTask(with: url) { data, _, error in
        if let error = error {
            completionHandler(nil, nil, error)
            return
        }
        guard let data = data else {
            completionHandler(nil, nil, NSError(domain: "EmptyData", code: -2))
            return
        }
        do {
            let response = try JSONDecoder().decode(WeatherResponse.self, from: data)
            completionHandler(response.main, response.name, nil)
        } catch {
            print("数据解析错误: \(error)")
            completionHandler(nil, nil, error)
        }
    }.resume()
}

第三步:调整调用逻辑

func retrieve() {
    fetchWeather(lat: latitudeValue, lon: longitudeValue) { weather, cityName, error in
        if let error = error {
            print("请求失败: \(error.localizedDescription)")
            return
        }
        guard let weather = weather else { return }
        print("温度: \(weather.temp ?? 0),湿度: \(weather.humidity ?? 0),城市: \(cityName ?? "")")
        // UI更新必须切到主线程执行
        DispatchQueue.main.async {
            self.humidityLabel.text = "湿度:\(weather.humidity ?? 0)%"
        }
    }
}

内容的提问来源于stack exchange,提问作者user14908036

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 17:45:02