Swift 尝试将 Codable 父 class 解码为其子 class 之一

Swift Attempt to a decode a Codable parent class as one of its subclasses

假设我有父 class A: Codable 和子 class 是 B1: AB2: A。我的应用程序中的另一个 class Main: Codable 有一个指向 A 的指针,它可以是 B1B2 但不能是 A(我有效地将 A 视为抽象 class)。

当我解码 Main 时,我 运行 遇到了一个问题,它被错误地解码为摘要 A 而不是 B1B2,即使存储在 A 中的值始终是 B1B2。我已经尝试在子 classes 中实现自定义 init(from decoder: Decoder)func encode(to encoder: Encoder)s,但是当我逐步执行被调用的 Main's decode logic in my running app, I never see those subclasses' 实现时。

这是因为 Main 有一个 A,甚至不知道尝试将其解码为 B1B2?我需要专门调用那些 subclasses 解码器吗?如果是后者,那些子classes 解码器将无法调用父解码器,因为那样会造成无限循环。

这是我的代码目前的样子:

class Main: Codable {
    let a: A
}

class A: Codable {

}

class B1: A {
    let b1Only: Int

    private enum CodingKeys: String, CodingKey {
        case b1Only
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        b1Only = try container.decode(Int.self, forKey: .b1Only)
        try super.init(from: decoder)
    }
    
    override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.b1Only, forKey: .b1Only)
        try super.encode(to: encoder)
    }
}

class B2: A {
    let b2Only: Int

    private enum CodingKeys: String, CodingKey {
        case b2Only
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        b2Only = try container.decode(Int.self, forKey: .b2Only)
        try super.init(from: decoder)
    }
    
    override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.b2Only, forKey: .b2Only)
        try super.encode(to: encoder)
    }
}

你需要在Main中有一个自定义的init(from:)并直接解码a到正确的子类

class Main: Codable {
    let a: A

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let object = try? container.decode(B1.self, forKey: .a) {
            a = object
        } else {
            a = try container.decode(B2.self, forKey: .a)
        }
    }
}