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

Swift中基于公共字段动态解码多类型Decodable对象的方案

Swift 基于响应类型动态选择Codable结构体解码

针对你需要根据resultType字段动态解码不同Codable结构体的场景,以下是两种简洁的实现方案:

方案1:使用枚举作为联合类型(推荐)

定义一个包含所有目标类型关联值的枚举,通过自定义解码逻辑先读取resultType,再匹配对应的结构体完成解码。这种方式类型安全,编译器会强制覆盖所有case,避免遗漏。

// 定义各类型的Result结构体
struct Result1: Codable {
    let resultType: String = "result1"
    let field1: String // 该类型独有字段
}

struct Result2: Codable {
    let resultType: String = "result2"
    let field2: Int // 该类型独有字段
}

// 定义联合枚举,作为所有Result类型的统一容器
enum ResultUnion: Codable {
    case result1(Result1)
    case result2(Result2)
    // 新增类型时只需添加对应case
    
    // 自定义解码逻辑
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let resultType = try container.decode(String.self, forKey: .resultType)
        
        switch resultType {
        case "result1":
            let result = try Result1(from: decoder)
            self = .result1(result)
        case "result2":
            let result = try Result2(from: decoder)
            self = .result2(result)
        default:
            throw DecodingError.dataCorruptedError(
                forKey: .resultType,
                in: container,
                debugDescription: "未知的resultType: \(resultType)"
            )
        }
    }
    
    // 自定义编码(若不需要编码可省略)
    func encode(to encoder: Encoder) throws {
        switch self {
        case .result1(let result): try result.encode(to: encoder)
        case .result2(let result): try result.encode(to: encoder)
        }
    }
    
    private enum CodingKeys: String, CodingKey {
        case resultType
    }
}

// 使用示例
do {
    let decodedResult = try JSONDecoder().decode(ResultUnion.self, from: responseData)
    switch decodedResult {
    case .result1(let res):
        // 处理Result1逻辑
        print(res.field1)
    case .result2(let res):
        // 处理Result2逻辑
        print(res.field2)
    }
} catch {
    print("解码失败:\(error)")
}

方案2:基于公共协议的可扩展解码

如果需要支持大量Result类型,可通过定义公共协议来统一识别类型,避免重复编写解码逻辑,新增类型时只需遵循协议即可。

// 定义公共协议,要求类型提供对应的resultType标识
protocol ResultIdentifiable: Codable {
    static var resultTypeKey: String { get }
}

// 让各Result结构体遵循协议
struct Result1: ResultIdentifiable {
    let resultType: String = "result1"
    let field1: String
    
    static var resultTypeKey: String { "result1" }
}

struct Result2: ResultIdentifiable {
    let resultType: String = "result2"
    let field2: Int
    
    static var resultTypeKey: String { "result2" }
}

// 解码工具类
enum DynamicResultDecoder {
    static func decode(from data: Data, supportedTypes: [ResultIdentifiable.Type]) throws -> ResultIdentifiable {
        // 临时解码仅获取resultType字段
        struct TempResult: Codable { let resultType: String }
        let temp = try JSONDecoder().decode(TempResult.self, from: data)
        
        // 匹配对应的目标类型
        guard let targetType = supportedTypes.first(where: { $0.resultTypeKey == temp.resultType }) else {
            throw DecodingError.dataCorruptedError(
                forKey: TempResult.CodingKeys.resultType,
                in: try data.keyedContainer(),
                debugDescription: "不支持的resultType: \(temp.resultType)"
            )
        }
        
        return try JSONDecoder().decode(targetType, from: data)
    }
    
    private static extension Data {
        func keyedContainer() throws -> KeyedDecodingContainer<TempResult.CodingKeys> {
            try JSONDecoder().container(keyedBy: TempResult.CodingKeys.self)
        }
    }
}

// 使用示例
do {
    let supportedTypes: [ResultIdentifiable.Type] = [Result1.self, Result2.self]
    let result = try DynamicResultDecoder.decode(from: responseData, supportedTypes: supportedTypes)
    
    switch result {
    case let res as Result1: print(res.field1)
    case let res as Result2: print(res.field2)
    default: break
    }
} catch {
    print("解码失败:\(error)")
}

方案对比

  • 枚举方案:类型安全,switch分支会被编译器检查,适合类型数量较少、固定的场景。
  • 协议方案:扩展性强,新增类型无需修改解码核心逻辑,适合类型较多或需要动态扩展的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:55:58