【问题标题】:Is Decodable inheritance even possible in Swift?在 Swift 中是否可以使用 Decodable 继承?
【发布时间】:2020-06-05 00:22:04
【问题描述】:

我通常使用从 Decodable 继承的结构来序列化我从后端提取的 JSON 数据。但是,我有一个应用程序,其中 JSON 有效负载与现有结构相同,但有一些细微差别。因此,我想要一个可解码结构,它继承自另一个可解码结构,如下所示:

class Party: Decodable {
    var theme: String

}

class PublicParty : Party {
    var address: String = ""
}

但是,当我发送以下 JSON 负载时,只有来自 Party 类的“主题”被解码,而来自 PublicParty 的“地址”仍然是“”:

{
"theme": "Black out or get out",
"address": "404 Mundus, Tabasko Beach 45778 WA"
}

Swift 代码:

func test(completion: @escaping(Result<PublicParty, Error>) -> ()) {
        guard let url = URL(string: "127.0.0.1:8000/test") else { return }

        URLSession.shared.dataTask(with: url) { (data, response, error) in

            // handle error
            if let error = error {
                completion(.failure(error))
                return
            }

            // decode data
            do {
                let search = try JSONDecoder().decode(PublicParty.self, from: data!)
                    print(search)
                completion(.success(search))
            } catch let error {
                completion(.failure(error))
            }

        }.resume()

}

由于我的前端/后端什么都没有,Swift 甚至允许这个功能吗?

【问题讨论】:

  • 结构不会从任何东西“继承”,像 Decodable 这样的协议不能被继承,像你的 Party 这样的 class 不是结构。请使用有意义的语言。
  • 在此线程上接受的答案应该会有所帮助:stackoverflow.com/questions/48238196/…
  • CSV、JSON 和 YAML 等常见的序列化格式没有继承的概念。 Swift 对此并不固执己见,它也没有引入自己的约定来划分对象的类型以及对象在层次结构中的位置。如果您想要一个带有"theme" 的JSON 有效负载,并且"address" 键是PublicParty,但只有一个"theme" 的对象是Party,那么这就是您需要的东西自己实施。
  • 有许多不同的方法可以做到这一点,并有不同的权衡。以下是一些想法:1) 特定端点的对象类型总是有一个单一的已知类型 2) 有效负载有一个像 __type 这样的字段,它携带一些标识符,它向您的应用发出信号,它应该由哪个应用解码。 YAML 更本机地支持这一点,其 ! myClass 类型注释语法。 3) 您可以检查对象的键,并确定一组特定键的类型。
  • 你完全正确,谢谢。但是,我得到了继承,请参阅解决方案。 @Alexander-ReinstateMonica

标签: swift swiftui swift5 decodable


【解决方案1】:

这行得通:

class Party: Decodable {
    var theme: String

}

class PublicParty : Party {
    var address: String = ""

     required init(from decoder: Decoder) throws {

        try super.init(from: decoder)

        let values = try decoder.container(keyedBy: CodingKeys.self)
        address = try values.decode(String.self, forKey: .address)
      }

    private enum CodingKeys: String, CodingKey
    {
        case address

    }
}

【讨论】:

    猜你喜欢
    • 2017-11-17
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多