在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