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

Swift Decodable如何实现支持Stripe返回动态data数组的通用Request结构体

问题原因

Decodable要求所有属性的类型都必须遵守Decodable协议,Any没有遵守该协议,所以编译器会抛出不遵守协议的错误。

解决方案1:使用泛型结构体(推荐)

Stripe的同个列表接口返回的data数组内元素类型是固定的,调用接口时你可以明确知道当前接口对应的业务对象类型,用泛型实现通用结构最合理。
首先先定义你需要的业务模型,比如退款模型:

// 先定义退款模型,遵守Decodable
struct Refund: Decodable {
    let id: String
    let object: String
    let amount: Int
    let balance_transaction: String?
    let charge: String
    let created: Int
    let currency: String
    // 其他需要的字段按需定义即可
}
// 同理可定义Card等其他业务模型

然后将原来的响应结构体改成泛型(这里将结构体名改为StripeListResponse更符合语义,你也可以保留原来的Request命名):

struct StripeListResponse<T: Decodable>: Decodable {
    var object: String
    var url: String
    var has_more: Bool
    var data: [T]
}

使用的时候,指定泛型类型即可:

// 解码退款列表响应时
let decoder = JSONDecoder()
let refundList = try decoder.decode(StripeListResponse<Refund>.self, from: jsonData)
// 解码卡片列表时,泛型替换为Card即可
let cardList = try decoder.decode(StripeListResponse<Card>.self, from: jsonData)
解决方案2:多类型枚举适配混合元素场景

如果确实存在data数组内同时包含多种不同类型对象的极端场景,可以定义一个枚举承载所有可能的业务类型,根据Stripe对象自带的object字段判断解码类型:

enum StripeObject: Decodable {
    case refund(Refund)
    case card(Card)
    // 其他可能的类型按需添加
    
    // 手动实现解码逻辑
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let objectType = try container.decode(String.self, forKey: .object)
        switch objectType {
        case "refund":
            let refund = try Refund(from: decoder)
            self = .refund(refund)
        case "card":
            let card = try Card(from: decoder)
            self = .card(card)
        default:
            // 处理未知类型,也可以抛自定义错误
            throw DecodingError.dataCorruptedError(forKey: .object, in: container, debugDescription: "未知的对象类型 \(objectType)")
        }
    }
    
    enum CodingKeys: String, CodingKey {
        case object
    }
}

此时你的响应结构体可以定义为:

struct StripeListResponse: Decodable {
    var object: String
    var url: String
    var has_more: Bool
    var data: [StripeObject]
}

使用时通过枚举匹配获取对应类型的对象即可:

for item in response.data {
    switch item {
    case .refund(let refund):
        // 处理退款对象
        print(refund.amount)
    case .card(let card):
        // 处理卡片对象
        print(card.last4)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 11:24:06