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

SwiftUI解析Yandex天气API JSON响应失败问题咨询

问题分析与修复方案

核心错误原因

当前解码失败的直接原因是**info结构体的字段与JSON不匹配**:API返回的JSON中info对象包含的是_h字段,但代码里定义的是h,导致Swift找不到对应key,触发keyNotFound错误。除此之外,还有多处类型不匹配、非可选字段缺失的问题,逐一修复如下:


具体修复步骤

1. 修正info结构体的字段映射

将info结构体中的h字段改为_h,对应JSON里的"_h":false:

struct info: Codable, Identifiable {
    let id = UUID()
    let n: Bool
    let geoid: Int
    let url: String
    let lat, lon: Int
    let tzinfo: tzinfo
    let def_pressure_mm, def_pressure_pa: Int
    let slug: String
    let zoom: Int
    let nr, ns, nsr, p: Bool
    let f, _h: Bool // 替换原h字段为_h
}

2. 修正geo_object结构体的可选类型

API返回的geo_object中district和locality是null,需将其改为可选类型:

struct geo_object: Codable, Identifiable {
    let id = UUID()
    let district: String? // 改为可选
    let locality: country? // 改为可选,适配JSON中的null值
    let province, country: country
}

3. 修正fact结构体的类型与缺失字段

返回的JSON中fact存在浮点型字段,且缺少accum_prec字段,需调整类型并设置可选:

struct fact : Codable, Identifiable {
    let id = UUID()
    let obs_time, uptime, temp, feels_like: Int
    let icon: icon
    let condition: condition
    let cloudness, prec_type, prec_prob: Int
    let prec_strength: Double // JSON中是0.25,原Int类型会报错
    let is_thunder: Bool
    let wind_speed: Double
    let wind_dir: wind_dir
    let pressure_mm, pressure_pa, humidity: Int
    let daytime: daytime
    let polar: Bool
    let season, source: String
    let accum_prec: [String: Double]? // 改为可选,JSON中无此字段
    let soil_moisture: Double
    let soil_temp, uv_index: Int
    let wind_gust: Double // JSON中是6.6,原Int类型会报错
}

4. 修正forecast结构体的缺失字段

返回的JSON片段中forecast仅包含部分字段,将未返回的字段改为可选:

struct forecast: Codable, Identifiable {
    let id = UUID()
    let date: String
    let date_ts, week: Int
    let sunrise: String
    let sunset, rise_begin, set_end: String? // 改为可选
    let moon_code: Int? // 改为可选
    let moon_text: String? // 改为可选
    let parts: parts? // 改为可选
    let hours: [hour]? // 改为可选
    let biomet: biomet?
}

5. 移除强制解包,添加错误处理

代码中try!和data!会直接触发崩溃,改用do-catch处理错误:

class WeatherApi {
    func getPost(completion: @escaping (Post?) -> ()){
        guard let url = URL(string: "https://api.weather.yandex.ru/v2/forecast?lat=50&lon=37") else {
            completion(nil)
            return
        }
        print("kek")
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        request.setValue("[key here]", forHTTPHeaderField: "X-Yandex-API-Key")
        URLSession.shared.dataTask(with: request){(data, _, error) in
            guard let data = data, error == nil else {
                print("请求错误:\(error?.localizedDescription ?? "未知错误")")
                completion(nil)
                return
            }
            do {
                let post = try JSONDecoder().decode(Post.self, from: data)
                print(post)
                DispatchQueue.main.async {
                    completion(post)
                }
            } catch {
                print("解码错误:\(error)")
                completion(nil)
            }
        }
        .resume()
    }
}

额外建议

  • 结构体名遵循Swift命名规范,首字母大写(如info改为Info、fact改为Fact),提升代码可读性。
  • 使用JSONDecoder的蛇形转驼峰策略,简化字段命名:
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    
    这样可以将now_dt改为nowDt、geo_object改为geoObject,更符合Swift风格。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 15:47:01