不用显式解码就可以使用Codable子类吗?

时间:2019-05-28 17:20:50

标签: swift

我使用struct MyThing:Codable { }解析JSON了几次。现在,我想使用class而不是struct,因为struct并不真正适合我需要完成的工作(可变性,一致性等),还有一些子类化。我尝试过:

class Beverage:Codable{
    var name:String = ""
}
class Beer:Beverage{
    var alcoholPercent:Double = 0
}

我不一定会在同一列表中收到多种不同类型的饮料的列表,比方说,我只想解码[Beer]的列表。如果我将json与单一啤酒(如{"name": "Hansa", "alcoholPercent": 5.4}一起尝试,并尝试将其解码为Beer类,如下所示:

let beer = try! JSONDecoder().decode(Beer.self, from: json.data(using: .utf8)!)

beer将具有name: HansaalcoholPercent: 0.0。名称正确,但是alcoholPercent是该类中的默认值。

有没有一种神奇的方法可以使子类自动符合Codable而无需显式设置每个变量的键/值?

有效:

class Beverage:Codable{
    var name:String = ""
}
class Beer:Beverage{
    var alcoholPercent:Double = 0

    enum CodingKeys:String, CodingKey{
        case alcoholPercent
    }

    required init(from decoder: Decoder) throws {
        let values = try! decoder.container(keyedBy: CodingKeys.self)
        self.alcoholPercent = try! values.decode(Double.self, forKey: .alcoholPercent)
        try super.init(from: decoder)
    }
}

使用此代码,我得到"Hansa"5.4。 为什么对于子类我必须显式遵循Codable,而对于基类却不必显式地遵循'--呢?没有所有手册代码,有没有办法做到这一点?我觉得这应该可以直接使用,而不需要必需的init。

1 个答案:

答案 0 :(得分:3)

您要提供的是init(from:)Beer覆盖的编译器综合。 Swift不会那样做。这已在Swift论坛上进行了讨论,例如in this thread。 Itai Ferber是负责Codable设计和实施的主要Apple工程师,因此您可以认为他的回答具有权威性。

如果从Codable中删除Beverage符合性,并将其直接添加到Beer(以及添加到Beverage的任何其他叶子类中),则可能会得到以下行为:想。不过,只有在您不需要Beverage本身的一致性时,这种方法才有用。