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

Swift使用Codable解析Open API数据失败,请求技术排查

Swift Codable解析Open-Meteo API无数据问题修复

你的代码主要存在几个核心问题,导致无法获取并解析数据,逐一排查修复如下:

1. URL格式错误(直接导致请求无法发起)

你定义的URL字符串中?后面有大量多余空格,URL(string:)无法识别这种格式的字符串,会返回nil,后续强制解包url!会直接崩溃,根本走不到请求逻辑。

修复:清理URL中的空格,正确的URL应该是:

static let url = URL(string: "https://api.open-meteo.com/v1/forecast?latitude=42.70&longitude=23.32&current_weather=true")

2. 字段名不匹配(解析失败的核心原因)

Open-Meteo API返回的当前天气字段是current_weather(带下划线),但你的Weather结构体中定义的是currentweather(无下划线),Codable默认按属性名匹配JSON字段,所以完全找不到对应值,解析直接失败。

修复:通过CodingKeys映射字段名,同时遵循Swift规范把结构体名改成大写开头:

struct CurrentWeather: Codable {
    var temperature: Double
    var time: String
    var weathercode: Double
    var winddirection: Double
    var windspeed: Double
}

struct Weather: Codable {
    var elevation: Double
    var latitude: Double
    var longitude: Double
    var timezone: String
    var timezone_abbreviation: String
    var utc_offset_seconds: Int
    var generationtime_ms: Double
    var currentWeather: CurrentWeather
    
    // 映射JSON下划线字段
    enum CodingKeys: String, CodingKey {
        case elevation, latitude, longitude, timezone, timezone_abbreviation, utc_offset_seconds, generationtime_ms
        case currentWeather = "current_weather"
    }
}

3. 错误处理过于简陋,无法定位问题

你用try?直接吞掉了解析错误,连哪里错了都不知道。换成do-catch捕获错误,同时增加网络错误、空数据的判断,才能快速定位问题。

修复:完善请求回调中的错误处理:

let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
    // 先处理网络请求错误
    if let error = error {
        print("请求失败: \(error.localizedDescription)")
        return
    }
    
    // 确保数据不为空
    guard let data = data else {
        print("未获取到响应数据")
        return
    }
    
    // 可选:打印原始JSON,方便对比字段
    if let jsonStr = String(data: data, encoding: .utf8) {
        print("原始响应JSON:\n\(jsonStr)")
    }
    
    // 解析数据并捕获错误
    do {
        let weather = try JSONDecoder().decode(Weather.self, from: data)
        RequestManager.temperature = weather.currentWeather.temperature
        print("解析成功,当前温度:\(RequestManager.temperature)")
    } catch {
        print("解析出错: \(error)")
    }
})

4. 冗余的请求头与不安全的强制解包

  • GET请求不需要设置Content-Type,这个字段是用来标识请求体的数据类型,GET没有请求体,直接删掉这行:request.setValue("application/json", forHTTPHeaderField: "Content-Type")
  • 不要用!强制解包url和data,用可选绑定安全处理,避免空值崩溃:
class func getWeatherData() {
    guard let url = url else {
        print("URL格式无效")
        return
    }
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    
    // 后续请求逻辑...
}

完整修复后的代码

Codable结构体

import Foundation

struct CurrentWeather: Codable {
    var temperature: Double
    var time: String
    var weathercode: Double
    var winddirection: Double
    var windspeed: Double
}

struct Weather: Codable {
    var elevation: Double
    var latitude: Double
    var longitude: Double
    var timezone: String
    var timezone_abbreviation: String
    var utc_offset_seconds: Int
    var generationtime_ms: Double
    var currentWeather: CurrentWeather
    
    enum CodingKeys: String, CodingKey {
        case elevation, latitude, longitude, timezone, timezone_abbreviation, utc_offset_seconds, generationtime_ms
        case currentWeather = "current_weather"
    }
}

RequestManager

import Foundation

class RequestManager {
    static let url = URL(string: "https://api.open-meteo.com/v1/forecast?latitude=42.70&longitude=23.32&current_weather=true")
    static var temperature: Double = 0.0
    
    class func getWeatherData() {
        guard let url = url else {
            print("URL格式无效")
            return
        }
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        
        let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
            if let error = error {
                print("请求失败: \(error.localizedDescription)")
                return
            }
            
            guard let data = data else {
                print("未获取到响应数据")
                return
            }
            
            if let jsonStr = String(data: data, encoding: .utf8) {
                print("原始响应JSON:\n\(jsonStr)")
            }
            
            do {
                let weather = try JSONDecoder().decode(Weather.self, from: data)
                RequestManager.temperature = weather.currentWeather.temperature
                print("解析成功,当前温度:\(RequestManager.temperature)")
            } catch {
                print("解析出错: \(error)")
            }
        })
        task.resume()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:36:27