当我不知道类型和类继承时,如何解码?

时间:2017-11-29 22:58:41

标签: swift inheritance swift4 codable

我有一个基类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,然后在decode()的{​​{1}}方法中,以某种方式检测正确的类并重定向?

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

如果有帮助:我有一个NSKeyedUnarchiver每个子类返回,所以我不必使用该类的名称作为其身份。

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

NSCoding并未弃用。我们仍然在通过init(coder:)从故事板中实例化UIViewControllers时使用它。

此外,如果您仍然不想使用NSCoding,则可以将InputOutputTypes存储到结构中并序列化改为磁盘。

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

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

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

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