gre*_*rey 8 swift swift-protocols codable
我正在尝试在 Swift 5.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
}
Run Code Online (Sandbox Code Playgroud)
但是,即使Wallet符合Codable
类型“帐户”不符合协议“可解码”
类型“帐户”不符合协议“可编码”
是否可以做出any符合Codable?
或者 Swift 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)
}
}
Run Code Online (Sandbox Code Playgroud)
但我已经恢复为只使用这个:
struct Account: Codable {
var id: String
var name: String
var cashWallets: [CashWallet]
var digitalWallets: [DigitalWallet]
}
Run Code Online (Sandbox Code Playgroud)
any Protocol我担心仅仅为了遵守依赖倒置原则而付出的性能开销是不值得的。
协议不符合自身,因此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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您暂时注释掉wallets,Xcode 14 会自动为您完成剩余的方法encode(to:),因此您只需编写 for 的循环即可wallets。
这是未来可能会改善的事情。Swift 无法自动生成这种一致性并没有什么深层次的原因。只是今天没有。
然而,正如 Alexander 所指出的,不可能以一般方式符合 Decodable,因为它需要一个init. 您必须知道要解码哪种类型,并且序列化数据不包含该信息(至少按照您描述的方式)。因此,您必须手写做出选择(例如,使用某种默认的钱包类型)。
| 归档时间: |
|
| 查看次数: |
2262 次 |
| 最近记录: |