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

Swift 自定义Decodable解码:将不同zone的blocks映射为对应类型数组

自定义Decodable实现JSON结构转业务模型

核心实现思路:解码时不直接把zones解析为固定结构的数组,而是先读取每个zone的name标识,动态决定blocks字段的解码类型,最终将同类型的block聚合到Root结构对应的独立数组属性中,全程保持类型安全,无需依赖无类型的Any/字典中转。

实现代码

首先定义内部使用的辅助类型,用于承接zones数组的原始结构:

// 匹配接口返回的zone名称标识
private enum ZoneIdentifier: String, Decodable {
    case zoneA, zoneB, zoneC, zoneD
}

// zones数组单个元素的临时解码结构
private struct RawZone: Decodable {
    let name: ZoneIdentifier
    let blockContainer: KeyedDecodingContainer<RawZone.CodingKeys>
    
    enum CodingKeys: String, CodingKey {
        case name, blocks
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(ZoneIdentifier.self, forKey: .name)
        // 持有blocks字段的解码容器,后续按需解析对应类型
        blockContainer = container
    }
}

给Root实现Decodable协议:

extension Root: Decodable {
    private enum RootCodingKeys: String, CodingKey {
        case zones
    }
    
    init(from decoder: Decoder) throws {
        // 初始化临时变量承接各类型的元素数组
        var elementsA: [ElementA] = []
        var elementsB: [ElementB] = []
        var elementsC: [ElementC] = []
        var elementsD: [ElementD] = []
        
        let rootContainer = try decoder.container(keyedBy: RootCodingKeys.self)
        // 解码得到所有原始zone数据
        let rawZones = try rootContainer.decode([RawZone].self, forKey: .zones)
        
        // 遍历每个zone,按name匹配对应类型解码blocks
        for rawZone in rawZones {
            switch rawZone.name {
            case .zoneA:
                elementsA = try rawZone.blockContainer.decode([ElementA].self, forKey: .blocks)
            case .zoneB:
                elementsB = try rawZone.blockContainer.decode([ElementB].self, forKey: .blocks)
            case .zoneC:
                elementsC = try rawZone.blockContainer.decode([ElementC].self, forKey: .blocks)
            case .zoneD:
                elementsD = try rawZone.blockContainer.decode([ElementD].self, forKey: .blocks)
            }
        }
        
        // 给结构体常量属性赋值
        self.elementsA = elementsA
        self.elementsB = elementsB
        self.elementsC = elementsC
        self.elementsD = elementsD
    }
}

适配说明

  • 只要ElementA/ElementB/ElementC/ElementD本身遵守Decodable协议,不需要额外实现自定义解码逻辑
  • 如果接口可能返回未定义的zone名称,在switch语句中增加default: break分支即可忽略未知zone,不会中断整体解码
  • 如果需要做容错处理(比如单个zone解析失败不影响整体返回),可以给单zone的解码逻辑包裹do-catch块自行处理错误
  • 该实现完全兼容Decodable原生的错误传递机制,字段缺失、类型不匹配等错误会正常抛出

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:27:16