在Swift中对KeyedDecodingContainer的子对象进行多态解码
下面的代码试图创建一个在Swift中对KeyedDecodingContainer的子对象进行多态解码,swift,codable,Swift,Codable,下面的代码试图创建一个Codable类型AnyBase,该类型允许您对Base的各种子类进行编码和解码。如前所述,in失败,因为它尝试使用getTypeFromCode通过字符串代码查找类型对象。但是,如果将注释掉的部分与硬编码类型一起使用,它会根据需要打印“Sub1” 是否有一种方法可以调整它以使用类似于getTypeFromCode的东西,并从init中删除硬编码类型 class Base: Codable { var foo: Int = 1 var codingTypeK
Codable
类型AnyBase
,该类型允许您对Base
的各种子类进行编码和解码。如前所述,in失败,因为它尝试使用getTypeFromCode
通过字符串代码查找类型对象。但是,如果将注释掉的部分与硬编码类型一起使用,它会根据需要打印“Sub1”
是否有一种方法可以调整它以使用类似于getTypeFromCode
的东西,并从init
中删除硬编码类型
class Base: Codable {
var foo: Int = 1
var codingTypeKey: String { fatalError("abstract") }
}
class Sub1: Base {
var sub1Prop: Int = 2
override var codingTypeKey: String { "sub1" }
enum CodingKeys: CodingKey {
case sub1Prop
}
override init() {
super.init()
}
required init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
sub1Prop = try c.decode(Int.self, forKey: .sub1Prop)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var c = encoder.container(keyedBy: CodingKeys.self)
try c.encode(sub1Prop, forKey: .sub1Prop)
try super.encode(to: encoder)
}
}
class Sub2: Base {
var sub2Prop: Int = 2
override var codingTypeKey: String { "sub2" }
}
func getTypeFromCode(_ typeCode: String) -> Base.Type {
if typeCode == "sub1" { return Sub1.self }
else if typeCode == "sub2" { return Sub2.self }
else { fatalError("bad type code") }
}
class AnyBase: Codable {
let base: Base
init(_ b: Base) { base = b }
required init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
let typeCode = try c.decode(String.self, forKey: .type)
/*if typeCode == "sub1" {
self.base = try c.decode(Sub1.self, forKey: .base)
} else if typeCode == "sub2" {
self.base = try c.decode(Sub2.self, forKey: .base)
} else {
fatalError("bad type code")
}*/
let typeObj = getTypeFromCode(typeCode)
self.base = try c.decode(typeObj, forKey: .base)
}
func encode(to encoder: Encoder) throws {
var c = encoder.container(keyedBy: CodingKeys.self)
try c.encode(base.codingTypeKey, forKey: .type)
try c.encode(base, forKey: .base)
}
enum CodingKeys: CodingKey {
case base, type
}
}
// To to round-trip encode/decode and get the right object back...
let enc = JSONEncoder()
let dec = JSONDecoder()
let sub = Sub1()
let any = AnyBase(sub)
let data = try! enc.encode(any)
let str = String(data:data, encoding:.utf8)!
print(str)
let any2 = try! dec.decode(AnyBase.self, from: data)
print(type(of:any2.base))
您可以创建一个
enum BaseType
方法,而不是getTypeFromCode(:)
方法,如
enum BaseType: String {
case sub1, sub2
var type: Base.Type {
switch self {
case .sub1: return Sub1.self
case .sub2: return Sub2.self
}
}
}
现在,在init(from:)
中,使用typeCode
作为rawValue
获取BaseType
,即
class AnyBase: Codable {
required init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
let typeCode = try c.decode(String.self, forKey: .type)
if let baseType = BaseType(rawValue: typeCode) {
self.base = try c.decode(baseType.type, forKey: .base)
} else {
fatalError("bad type code")
}
}
//rest of the code...
}
您可以创建一个
enum BaseType
方法,而不是getTypeFromCode(:)
方法,如
enum BaseType: String {
case sub1, sub2
var type: Base.Type {
switch self {
case .sub1: return Sub1.self
case .sub2: return Sub2.self
}
}
}
现在,在init(from:)
中,使用typeCode
作为rawValue
获取BaseType
,即
class AnyBase: Codable {
required init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
let typeCode = try c.decode(String.self, forKey: .type)
if let baseType = BaseType(rawValue: typeCode) {
self.base = try c.decode(baseType.type, forKey: .base)
} else {
fatalError("bad type code")
}
}
//rest of the code...
}
我只是测试了一下,它不起作用。像我未注释的示例一样,它解码并创建一个
Base
,而不是所需的Sub1
。我刚刚测试了它,但它不起作用。与我未注释的示例一样,它解码并创建一个Base
,而不是所需的Sub1
。