首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有可能使“任何协议”符合可编码的标准?

是否有可能使“任何协议”符合可编码的标准?
EN

Stack Overflow用户
提问于 2022-07-26 12:47:36
回答 1查看 267关注 0票数 6

我试图在SWIFT5.7中创建一个带有Codable结构的[any Protocol]结构

代码语言:javascript
复制
struct Account: Codable {
    var id: String
    var name: String
    var wallets: [any Wallet]
}

protocol Wallet: Codable {
    var id: String { get set }
    //... other codable properties
}

然而,即使Wallet符合Codable,我也会得到这些错误

类型‘帐户’不符合协议‘可解码’类型‘帐户’不符合协议‘可编码’

是否有可能使any符合Codable

或者,斯威夫特5.7仍然不可能做到这一点?

编辑:如前所述,您必须实现自己的一致性。我就是这样做的:

代码语言:javascript
复制
protocol Wallet: Identifiable, Codable {
    var id: String { get set }
}

struct DigitalWallet: Wallet {
    var id: String
    // other properties
}

struct CashWallet: Wallet {
    var id: String
    // other properties
}

struct Account {
    var id: String
    var name: String
    var wallets: [any Wallet]
}

extension Account: Codable {
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case digitalWallet
        case cashWallet
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        id = try values.decode(String.self, forKey: .id)
        name = try values.decode(String.self, forKey: .name)

        let dW = try values.decode([DigitalWallet].self, forKey: .digitalWallet)
        let cW = try values.decode([CashWallet].self, forKey: .cashWallet)
        wallets = []
        wallets.append(contentsOf: dW)
        wallets.append(contentsOf: cW)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)

        var digitalWallet: [DigitalWallet] = []
        var cashWallet: [CashWallet] = []

        wallets.forEach { wallet in
            if wallet is DigitalWallet {
                digitalWallet.append(wallet as! DigitalWallet)
            } else if wallet is CashWallet {
                cashWallet.append(wallet as! CashWallet)
            }
        }
        try container.encode(digitalWallet, forKey: .digitalWallet)
        try container.encode(cashWallet, forKey: .cashWallet)
    }
}

但我又回到了用这个代替:

代码语言:javascript
复制
struct Account: Codable {
    var id: String
    var name: String
    var cashWallets: [CashWallet]
    var digitalWallets: [DigitalWallet]
}

我担心any Protocol的性能开销不值得仅仅遵循依赖反转原则。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-26 14:08:16

协议不符合自己的要求,因此any Wallet本身是不可编码的,因此您不会在这里获得自动一致性,也不会自动处理数组。但你可以自己处理,没有麻烦:

代码语言:javascript
复制
extension Account: Encodable {
    enum CodingKeys: CodingKey {
        case id
        case name
        case wallets
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.id, forKey: .id)
        try container.encode(self.name, forKey: .name)

        var walletContainer = container.nestedUnkeyedContainer(forKey: .wallets)
        for wallet in wallets {
            try walletContainer.encode(wallet)
        }
    }
}

如果您暂时注释掉wallets,Xcode 14将自动为您完成encode(to:)方法的其余部分,因此只需为wallets编写循环即可。

这种情况今后可能会有所改善。Swift不能自动生成这种一致性没有深层次的原因。只是今天不行。

然而,正如亚历山大所指出的,它不可能以一般的方式符合可解码,因为它需要一个init。您必须知道要解码哪种类型,而序列化的数据不包括这些信息(至少您已经描述了这种信息)。因此,您必须选择手写(例如,使用默认的Wallet类型)。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73123640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档