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

SwiftUI使用带枚举的Codable解析JSON后无法提取实际值如何解决?

解决方案

你自定义的Datum是带关联值的Swift枚举,要取出内部存储的值可以用以下3种常见方案,按使用便捷度排序:


方案1:给枚举增加便捷取值属性(最推荐)

直接在Datum枚举定义中增加两个计算属性,后续取值无需每次写匹配逻辑:

enum Datum: Codable {
    case dInteger(Int)
    case dString(String)
    
    // 新增以下两个计算属性
    var stringValue: String? {
        guard case .dString(let value) = self else { return nil }
        return value
    }
    
    var intValue: Int? {
        guard case .dInteger(let value) = self else { return nil }
        return value
    }

    // 原有init和encode逻辑保持不变
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Int.self) {
            self = .dInteger(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .dString(x)
            return
        }
        throw DecodingError.typeMismatch(Datum.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Datum"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .dInteger(let x):
            try container.encode(x)
        case .dString(let x):
            try container.encode(x)
        }
    }
}

使用时直接调用属性即可:

// 取时间字符串
let timeStr = dataStore.topLevels[0].series[0].data[0][0].stringValue ?? ""
// 取数值
let demandValue = dataStore.topLevels[0].series[0].data[0][1].intValue ?? 0

方案2:临时匹配枚举值

不需要修改枚举定义,单次取值时直接用if case/switch匹配关联值:

// 取第一个元素的字符串值
let firstDatum = dataStore.topLevels[0].series[0].data[0][0]
if case .dString(let time) = firstDatum {
    print(time) // 输出 20210522T04Z
}

// 取第二个元素的整数值
let secondDatum = dataStore.topLevels[0].series[0].data[0][1]
if case .dInteger(let value) = secondDatum {
    print(value) // 输出 438877
}

方案3:优化解析逻辑直接生成可用结构体(适合长期维护)

由于你的data子数组结构固定:第0位是时间字符串、第1位是需求数值,你可以直接在解析层就把二维枚举数组转成业务结构体,后续完全不需要处理枚举:

  1. 先定义业务结构体:
struct DemandPoint: Codable {
    let time: String
    let value: Int
}
  1. 自定义DemandPoint的解析逻辑:
extension DemandPoint {
    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        // 解析第一个元素为字符串
        time = try container.decode(String.self)
        // 解析第二个元素为整数
        value = try container.decode(Int.self)
    }
}
  1. 修改Series的data属性定义:
struct Series: Codable {
    let seriesID, name: String
    // 把原来的[[Datum]]改成[DemandPoint]
    let data: [DemandPoint]

    enum CodingKeys: String, CodingKey {
        case seriesID = "series_id"
        case name, data
    }
}

修改后解析出来的data直接是DemandPoint数组,取值更简单:

let point = dataStore.topLevels[0].series[0].data[0]
print(point.time) // 直接输出时间字符串
print(point.value) // 直接输出数值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 11:54:10