【问题标题】:How can I decode when I don't know the type, with class inheritance?当我不知道类型时如何使用类继承进行解码?
【发布时间】:2017-11-29 22:58:40
【问题描述】:

我有一个基类Action,它是一个Operation。它有一堆粗鲁的Operation 东西(KVO 和所有这些)。基类本身实际上不需要编码/解码任何东西。

class Action : Operation, Codable {
    var _executing = false
    ...
}

我有一堆Action 子类,比如DropboxUploadAction,它们直接用他们定义的Input 结构实例化:

let actionInput = DropboxUploadAction.Input.init(...)
ActionManager.shared.run(DropboxUploadAction.init(actionInput, data: binaryData), completionBlock: nil)

子类如下所示:

class DropboxUploadAction : Action {
    struct Input : Codable {
        var guid: String
        var eventName: String
        var fileURL: URL?
        var filenameOnDropbox: String
        var share: Bool
    }

    struct Output : Codable {
        var sharedFileLink: String?
        var dropboxPath: String?
    }

    var input: Input
    var output: Output

    ...

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        input = try values.decode(Input.self, forKey: .input)
        output = try values.decode(Output.self, forKey: .output)
        let superDecoder = try values.superDecoder()
        try super.init(from: superDecoder)
    }

    fileprivate enum CodingKeys: String, CodingKey {
        case input
        case output
    }

    override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(input, forKey: .input)
        try container.encode(output, forKey: .output)
        try super.encode(to: container.superEncoder())
    }
}

当某些情况发生时,例如互联网连接丢失,这些类需要序列化到磁盘以供以后使用。没关系,因为当时我有对它们的引用并且可以用JSONEncoder().encode(action) 对它们进行编码,没问题。

但后来当我想反序列化它们时,我需要指定类的类型,我不知道它是什么。我有一些数据,我知道它可以解码为继承自Action 的类,但我不知道它是哪个子类。我不愿意在文件名中对其进行编码。有没有办法将其解码为基类Action,然后在Action的decode()方法中,以某种方式检测到正确的类并重定向?

过去我使用NSKeyedUnarchiver.setClass() 来处理这个问题。但我不知道如何使用 Swift 4 的 Codable 来做到这一点,而且我知道 NSCoding 现在已弃用,所以我不应该再使用 NSKeyedUnarchiver...

如果有帮助:我有一个 struct Types : OptionSet, Codable,每个子类都会返回它,所以我不必使用类的名称作为其标识。

感谢您的帮助!

【问题讨论】:

标签: swift inheritance swift4 codable


【解决方案1】:

呃NSCoding 没有被弃用。当通过init(coder:) 从情节提要中实例化 UIViewControllers 时,我们仍然使用它。

另外,如果您仍然不想使用NSCoding,您可以只将Input、Output 和Types 存储到结构体中,然后将其序列化到磁盘。

struct SerializedAction {
  let input: Input
  let output: Output
  let type: Type
}

在需要时,您可以对其进行解码并确定正确的Action 以通过type 属性使用您的输入/输出进行初始化。

class DropboxAction: Action {
  ...
  init(input: Input, output: Output) {
  ...
  }
}

您不一定需要对整个 Action 对象进行编码。

【讨论】:

  • 谢谢。与此同时,我确实已经得出了相同的结论(仅对输入进行编码),所以我会接受这个作为答案
猜你喜欢
  • 1970-01-01
  • 2011-10-04
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
  • 2010-12-09
  • 2014-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多