当我不知道类型时如何使用 class 继承进行解码?
How can I decode when I don't know the type, with class inheritance?
我有一个基数 class Action
,它是一个 Operation
。它里面有一堆笨拙的 Operation
东西(KVO 等等)。基础 class 本身实际上不需要 encode/decode 任何东西。
class Action : Operation, Codable {
var _executing = false
...
}
我有一堆 Action
sub-classes,比如 DropboxUploadAction
,它们直接用它们定义的 Input
结构实例化:
let actionInput = DropboxUploadAction.Input.init(...)
ActionManager.shared.run(DropboxUploadAction.init(actionInput, data: binaryData), completionBlock: nil)
下面是子class的样子:
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())
}
}
当某些情况发生时,例如互联网连接丢失,这些 classes 需要序列化到磁盘以备后用。没关系,因为当时我有对它们的引用并且可以用 JSONEncoder().encode(action)
对它们进行编码,没问题。
但是后来我想反序列化它们时,我需要指定class的类型,但我不知道它是什么。我有一些数据,我知道它可以解码为继承自 Action
的 class,但我不知道它是哪个子 class。我讨厌在文件名中对其进行编码。有没有办法将它解码为基础 class Action
,然后在 Action
的 decode()
方法中,以某种方式检测正确的 class 并重定向?
过去我用 NSKeyedUnarchiver.setClass()
来处理这个问题。但我不知道如何用 Swift 4 的 Codable
做到这一点,我知道 NSCoding 现在已被弃用所以我不应该再使用 NSKeyedUnarchiver
...
如果有帮助:我有一个 struct Types : OptionSet, Codable
,每个子 class returns,所以我不必使用 class 的名称作为它的身份。
感谢您的帮助!
呃 NSCoding
没有弃用。我们仍然在通过 init(coder:)
从故事板实例化 UIViewController 时使用它。
此外,如果您仍然不想使用 NSCoding
,您可以将 Input
、Output
和 Types
存储到结构中并序列化它改为磁盘。
struct SerializedAction {
let input: Input
let output: Output
let type: Type
}
需要时,您可以对其进行解码并确定正确的 Action
以通过 type
属性 使用您的 input/output 进行初始化。
class DropboxAction: Action {
...
init(input: Input, output: Output) {
...
}
}
您不一定需要对整个 Action
对象进行编码。
我有一个基数 class Action
,它是一个 Operation
。它里面有一堆笨拙的 Operation
东西(KVO 等等)。基础 class 本身实际上不需要 encode/decode 任何东西。
class Action : Operation, Codable {
var _executing = false
...
}
我有一堆 Action
sub-classes,比如 DropboxUploadAction
,它们直接用它们定义的 Input
结构实例化:
let actionInput = DropboxUploadAction.Input.init(...)
ActionManager.shared.run(DropboxUploadAction.init(actionInput, data: binaryData), completionBlock: nil)
下面是子class的样子:
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())
}
}
当某些情况发生时,例如互联网连接丢失,这些 classes 需要序列化到磁盘以备后用。没关系,因为当时我有对它们的引用并且可以用 JSONEncoder().encode(action)
对它们进行编码,没问题。
但是后来我想反序列化它们时,我需要指定class的类型,但我不知道它是什么。我有一些数据,我知道它可以解码为继承自 Action
的 class,但我不知道它是哪个子 class。我讨厌在文件名中对其进行编码。有没有办法将它解码为基础 class Action
,然后在 Action
的 decode()
方法中,以某种方式检测正确的 class 并重定向?
过去我用 NSKeyedUnarchiver.setClass()
来处理这个问题。但我不知道如何用 Swift 4 的 Codable
做到这一点,我知道 NSCoding 现在已被弃用所以我不应该再使用 NSKeyedUnarchiver
...
如果有帮助:我有一个 struct Types : OptionSet, Codable
,每个子 class returns,所以我不必使用 class 的名称作为它的身份。
感谢您的帮助!
呃 NSCoding
没有弃用。我们仍然在通过 init(coder:)
从故事板实例化 UIViewController 时使用它。
此外,如果您仍然不想使用 NSCoding
,您可以将 Input
、Output
和 Types
存储到结构中并序列化它改为磁盘。
struct SerializedAction {
let input: Input
let output: Output
let type: Type
}
需要时,您可以对其进行解码并确定正确的 Action
以通过 type
属性 使用您的 input/output 进行初始化。
class DropboxAction: Action {
...
init(input: Input, output: Output) {
...
}
}
您不一定需要对整个 Action
对象进行编码。