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

如何将NOAA天气JSON解码为Swift结构体

Swift 解析混合类型数组(@context字段处理方案)

核心思路

@context是混合类型数组(包含字符串和对象),而Swift数组要求元素类型统一,因此用枚举封装两种可能的类型,让枚举实现Codable协议,即可完成解析。

具体实现代码

1. 定义Context结构体(对应数组中的对象元素)

先把数组中第二个元素的对象结构映射为Swift结构体:

struct Context: Codable {
    let version: String
    let wx: String
    let geo: String
    let unit: String
    let vocab: String
    
    // 处理JSON中带@的键名
    enum CodingKeys: String, CodingKey {
        case version = "@version"
        case wx
        case geo
        case unit
        case vocab = "@vocab"
    }
}

2. 定义枚举封装混合类型

创建枚举ContextElement,包含字符串和Context对象两种情况,并实现Codable协议:

enum ContextElement: Codable {
    case string(String)
    case context(Context)
    
    // 自定义解码逻辑
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        // 先尝试解码为字符串
        if let stringValue = try? container.decode(String.self) {
            self = .string(stringValue)
        }
        // 失败则尝试解码为Context对象
        else if let contextValue = try? container.decode(Context.self) {
            self = .context(contextValue)
        }
        // 都不符合则抛出错误
        else {
            throw DecodingError.dataCorruptedError(
                in: container,
                debugDescription: "无法解析为字符串或Context对象"
            )
        }
    }
    
    // 自定义编码逻辑(若不需要编码可省略,但建议保留协议完整性)
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let value):
            try container.encode(value)
        case .context(let value):
            try container.encode(value)
        }
    }
}

3. 在主结构体中使用枚举类型

在顶层结构体中,将@context字段的类型设为[ContextElement],并通过CodingKeys映射JSON键名:

struct WeatherFeature: Codable {
    let context: [ContextElement]
    let type: String
    let geometry: Geometry
    let properties: Properties
    
    enum CodingKeys: String, CodingKey {
        case context = "@context"
        case type
        case geometry
        case properties
    }
}

// 你已实现的其他结构体示例(按需求补充完整)
struct Geometry: Codable {
    let type: String
    let coordinates: [[[Double]]]
}

struct Properties: Codable {
    let units: String
    let forecastGenerator: String
    let generatedAt: String
    let updateTime: String
    let validTimes: String
    let elevation: Elevation
    let periods: [Period]
    
    // 内部结构体(Elevation、Period等)按你已有的实现编写即可
}

4. 解析示例

使用JSONDecoder解析API返回数据时,即可正常处理@context字段:

let jsonData = // 你的API返回数据
do {
    let weatherFeature = try JSONDecoder().decode(WeatherFeature.self, from: jsonData)
    // 遍历访问@context内容
    for element in weatherFeature.context {
        switch element {
        case .string(let url):
            print("Context URL: \(url)")
        case .context(let ctx):
            print("Context版本: \(ctx.version)")
            print("WX本体地址: \(ctx.wx)")
        }
    }
} catch {
    print("解析错误: \(error)")
}

说明

  • 枚举的自定义Codable实现是核心,通过singleValueContainer判断当前元素类型,选择对应解码方式。
  • 若仅需解码无需编码,可只实现init(from:)方法,但为了协议完整性建议保留encode(to:)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 11:13:23