gpt4 book ai didi

swift - 使协议(protocol)可编码并将其存储在数组中

转载 作者:行者123 更新时间:2023-12-02 02:54:35 25 4
gpt4 key购买 nike

我有 Animal 协议(protocol),其中包含 2 个符合它的结构和一个存储 Animals 列表的 Farm 结构。然后,我使它们都符合 Codable 以将其存储在文件中,但它会引发错误 cannot automatically synthesize 'Encodable' because '[Animal]' does not conform to 'Encodable'
我理解为什么会发生这种情况,但我找不到好的解决方案。如何使数组只接受 Codable 和 Animal,而不将 Animal 标记为 Codable,这样就不会发生此问题,例如 var animals = [Codable & Animal] ? (或任何其他解决方法)。谢谢

protocol Animal: Codable {
var name: String { get set }
var sound: String { get set }
}

struct Cow: Animal {
var name = "Cow"
var sound = "Moo!"
}

struct Duck: Animal {
var name = "Duck"
var sound = "Quack!"
}

struct Farm: Codable {

var name = "Manor Farm"
// this is where the error is shown
var animals = [Animal]()

}

- 编辑 -
当我将它们更改为一个类时,它看起来像这样:
class Animal: Codable {
var name = ""
var sound = ""
}

class Duck: Animal {
var beakLength: Int

init(beakLength: Int) {
self.beakLength = beakLength
super.init()

name = "Duck"
sound = "Quack!"
}

required init(from decoder: Decoder) throws {
// works, but now I am required to manually do this?
fatalError("init(from:) has not been implemented")
}
}

如果我没有其他属性,它会起作用,但是一旦我添加了一个,我就需要引入一个初始化程序,然后我需要从解码器初始化程序中包含初始化程序,它删除了 Codable 提供的自动转换。因此,要么我为我扩展的每个类手动执行此操作,要么我可以强制转换变量(如 var beakLength: Int! )以删除对初始化程序的要求。但是有没有别的办法?这似乎是一个简单的问题,但解决它使它变得非常困惑,我不喜欢。另外,当我使用这种方法从文件中保存/加载时,似乎没有保存数据

最佳答案

您可以通过 2 种方式执行此操作:

1 解决方案 - 使用包装器:

protocol Animal {}

struct Cow: Animal, Codable {
}

struct Duck: Animal, Codable {
}

struct Farm: Codable {
let animals: [Animal]

private enum CodingKeys: String, CodingKey {
case animals
}

func encode(to encoder: Encoder) throws {
let wrappers = animals.map { AnimalWrapper($0) }
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(wrappers, forKey: .animals)
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let wrappers = try container.decode([AnimalWrapper].self, forKey: .animals)
self.animals = wrappers.map { $0.animal }
}
}

fileprivate struct AnimalWrapper: Codable {
let animal: Animal

private enum CodingKeys: String, CodingKey {
case base, payload
}

private enum Base: Int, Codable {
case cow
case duck
}

init(_ animal: Animal) {
self.animal = animal
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let base = try container.decode(Base.self, forKey: .base)

switch base {
case .cow:
self.animal = try container.decode(Cow.self, forKey: .payload)
case .duck:
self.animal = try container.decode(Duck.self, forKey: .payload)
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

switch animal {
case let payload as Cow:
try container.encode(Base.cow, forKey: .base)
try container.encode(payload, forKey: .payload)
case let payload as Duck:
try container.encode(Base.duck, forKey: .base)
try container.encode(payload, forKey: .payload)
default:
break
}
}
}


2 解决方案 - 使用枚举
struct Cow: Codable {
}

struct Duck: Codable {
}

enum Animal {
case cow(Cow)
case duck(Duck)
}

extension Animal: Codable {
private enum CodingKeys: String, CodingKey {
case base, payload
}

private enum Base: Int, Codable {
case cow
case duck
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let base = try container.decode(Base.self, forKey: .base)
switch base {
case .cow:
self = .cow(try container.decode(Cow.self, forKey: .payload))
case .duck:
self = .duck(try container.decode(Duck.self, forKey: .payload))
}
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .cow(let payload):
try container.encode(Base.cow, forKey: .base)
try container.encode(payload, forKey: .payload)
case .duck(let payload):
try container.encode(Base.duck, forKey: .base)
try container.encode(payload, forKey: .payload)
}
}
}

关于swift - 使协议(protocol)可编码并将其存储在数组中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50205373/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com