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

如何从Codable响应模型提取name字段的FirstKey值或字符串内容

问题解决:Codable处理多格式name字段并提取值

问题背景

服务器返回的JSON中,name字段存在两种格式:

  • 格式1:包含First数组的对象数组,示例:[{"First": ["DSR"]}]
  • 格式2:直接字符串,示例:"Deepak Singh Rawat"

已通过NameUnion枚举实现解码,但需要提取对应的值(First数组中的内容或直接字符串)。

现有代码问题

读取响应代码存在两处错误:

  • 重复定义abModel变量
  • 使用未定义的response变量

解决方案

1. 优化模型,添加计算属性直接获取姓名

修改NameUnion枚举,新增计算属性displayName,自动处理两种格式的取值逻辑:

enum NameUnion: Codable {
    case nameElementArray([NameElement])
    case string(String)

    // 新增计算属性,直接返回要显示的姓名
    var displayName: String {
        switch self {
        case .nameElementArray(let elements):
            // 取第一个元素的firstKey数组的第一个值,为空则返回空字符串
            return elements.first?.firstKey?.first ?? ""
        case .string(let name):
            return name
        }
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode([NameElement].self) {
            self = .nameElementArray(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(NameUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for NameUnion"))
    }

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

2. 修正读取响应代码

修复变量定义错误,并演示如何遍历提取每个元素的姓名:

do {
    if let path = Bundle.main.path(forResource: "jsonfilename", ofType: "json") {
        let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
        let nameModel = try JSONDecoder().decode(NameModel.self, from: data)
        
        // 遍历所有元素,提取姓名
        for element in nameModel {
            if let nameUnion = element.name {
                print("提取到的姓名:\(nameUnion.displayName)")
            }
        }
    }
} catch {
    print("解码失败:\(error.localizedDescription)")
}

3. 可选优化:简化NameElement取值逻辑

如果NameElement中First数组只会有一个元素,可以修改firstKey的类型为String?,简化后续取值:

struct NameElement: Codable {
    var firstKey: String?

    enum CodingKeys: String, CodingKey {
        case firstKey = "First"
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        // 直接取数组第一个元素
        firstKey = try values.decodeIfPresent([String].self, forKey: .firstKey)?.first
    }
}

对应displayName的逻辑可简化为:

var displayName: String {
    switch self {
    case .nameElementArray(let elements):
        return elements.first?.firstKey ?? ""
    case .string(let name):
        return name
    }
}

效果验证

运行修正后的代码,会输出:

提取到的姓名:DSR
提取到的姓名:Deepak Singh Rawat

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 20:40:31