我试图在SWIFT5.7中创建一个带有Codable结构的[any Protocol]结构
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仍然不可能做到这一点?
编辑:如前所述,您必须实现自己的一致性。我就是这样做的:
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)
}
}但我又回到了用这个代替:
struct Account: Codable {
var id: String
var name: String
var cashWallets: [CashWallet]
var digitalWallets: [DigitalWallet]
}我担心any Protocol的性能开销不值得仅仅遵循依赖反转原则。
发布于 2022-07-26 14:08:16
协议不符合自己的要求,因此any Wallet本身是不可编码的,因此您不会在这里获得自动一致性,也不会自动处理数组。但你可以自己处理,没有麻烦:
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类型)。
https://stackoverflow.com/questions/73123640
复制相似问题