我正在使用 Codable 协议(protocol)序列化和反序列化继承的类。我成功地将整个模型序列化为 JSON,但在反序列化 JSON 时遇到问题。这是我的数据结构的样子。我的应用程序的某些部分的工作方式如下例所示,此时我们要更改整个数据结构将需要做太多工作。
class Base: Codable {
let baseValue: String
init(baseValue :String) {
self.baseValue = baseValue
}
enum SuperCodingKeys: String, CodingKey {
case baseValue
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: SuperCodingKeys.self)
try container.encode(baseValue, forKey: .baseValue)
}
}
class Child1: Base {
let child1Value: Int
init(child1Value: Int, baseValue: String) {
self.child1Value = child1Value
super.init(baseValue: baseValue)
}
private enum CodingKeys: String, CodingKey {
case child1Value
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.child1Value = try container.decode(Int.self, forKey: .child1Value)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(child1Value, forKey: .child1Value)
try super.encode(to: encoder)
}
}
class Child2: Base {
let child2Value: Int
init(child2Value: Int, baseValue: String) {
self.child2Value = child2Value
super.init(baseValue: baseValue)
}
private enum CodingKeys: String, CodingKey {
case child2Value
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.child2Value = try container.decode(Int.self, forKey: .child2Value)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(child2Value, forKey: .child2Value)
try super.encode(to: encoder)
}
}
class DataManager: Codable {
var bases: [Base] = []
init(bases: [Base]) {
self.bases = bases
}
}
这就是我如何为 DataManger 添加值(value)(顺便说一句,在我的应用程序中,这是一个单例类,它保存应用程序的全部数据。我正在尝试在此 DataManager 类上实现 Codable 协议(protocol))
let child1 = Child1(child1Value: 1, baseValue: "Child1Value_Base")
let child2 = Child2(child2Value: 2, baseValue: "Child2Value_Base")
let dataManager = DataManager(bases: [])
dataManager.bases.append(child1 as Base)
dataManager.bases.append(child2 as Base)
我正在使用 JSONEncoder() 通过此代码将模型编码为数据。到目前为止它运行良好。
let dataManagerData = try JSONEncoder().encode(dataManager)
print(String(data: dataManagerData, encoding: .utf8))
这就是 json 编码后的样子
{
"bases":[{
"child1Value":1,
"baseValue":"Child1Value_Base"
},
{
"child2Value":2,
"baseValue":"Child2Value_Base"
}]
}
因此,当我尝试使用下面的代码解码此 JSON 时,我只能将其解码到 Base(父类)级别,而不能解码到子级别。
let dataManager = try JSONDecoder().decode(DataManager.self, from: dataManagerData)
这就是我能从中得到的。
{
"bases":[{
"baseValue":"Child1Value_Base"
},
{
"baseValue":"Child2Value_Base"
}]
}
为了解决这个问题,我尝试使用这种方式手动解码,但是 JSONDecoder 给了我 0 个碱基数。
class DataManager: Codable {
var bases: [Base] = []
init(bases: [Base]) {
self.bases = bases
}
private enum CodingKeys: String, CodingKey {
case bases
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
// I think decoder is trying to decode the bases object based on Child1 or Child2 class and it fail.
if let value = try? container.decode(Child1.self, forKey: .bases) {
bases.append(value as Base)
} else if let value = try? container.decode(Child2.self, forKey: .bases){
bases.append(value as Base)
}
} catch {
print(error)
}
}
}
所以我的问题是
- 如何根据各自的子类反序列化这个基数组并将它们添加到 DataManager 中?
- 在“init(from detector: Decoder)”方法中是否有任何方法可以获取键的值并一一迭代它们以解码到各自的类。
最佳答案
如果有人遇到同样的问题,我找到了以下解决方案。
class DataManager: Codable {
var bases: [Base] = []
init(bases: [Base]) {
self.bases = bases
}
private enum CodingKeys: String, CodingKey {
case bases
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
var list = try container.nestedUnkeyedContainer(forKey: DataManager.CodingKeys.bases)
while !list.isAtEnd {
if let child1 = try? list.decode(Child1.self) {
bases.append(child1 as Base)
} else if let child2 = try? list.decode(Child2.self) {
bases.append(child2 as Base)
}
}
}
}
关于ios - 可通过继承进行编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58102590/