Reputation: 6804
I have a base class Action
, which is an Operation
. It has a bunch of crufty Operation
stuff in it (KVO and all that). The base class itself doesn't actually need to encode/decode anything.
class Action : Operation, Codable {
var _executing = false
...
}
I have a bunch of Action
sub-classes, like DropboxUploadAction
, which are directly instantiated with an Input
struct they define:
let actionInput = DropboxUploadAction.Input.init(...)
ActionManager.shared.run(DropboxUploadAction.init(actionInput, data: binaryData), completionBlock: nil)
Here's what the subclasses look like:
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())
}
}
When some situations occur such as a loss of internet connectivity, these classes need to be serialized to disk for later. That's fine, because at the time I have references to them and can encode them with JSONEncoder().encode(action)
, no problem.
But later when I want to deserialize them, I need to specify the type of the class and I don't know what it is. I have some data and I know it can be decoded to a class that inherits from Action
, but I don't know which subclass it is. I'm loathe to encode that in the filename. Is there some way to decode it as the base class Action
, then in the decode()
method of Action
, somehow detect the proper class and redirect?
In the past I've used NSKeyedUnarchiver.setClass()
to handle this. But I don't know how to do that with Swift 4's Codable
, and I understand that NSCoding is deprecated now so I shouldn't use NSKeyedUnarchiver
anymore...
If it helps: I have a struct Types : OptionSet, Codable
which each subclass returns, so I don't have to use the name of the class as its identity.
Thanks for any help!
Upvotes: 2
Views: 414
Reputation: 443
Uhhh NSCoding
isn't deprecated. We still use it when instantiating UIViewControllers from storyboard via init(coder:)
.
Also, if you still don't want to use NSCoding
, you can just store the Input
, Output
and Types
to a struct and serialize that to disk instead.
struct SerializedAction {
let input: Input
let output: Output
let type: Type
}
When needed, you can decode that and decide the correct Action
to initialize with your input/output via the type
property.
class DropboxAction: Action {
...
init(input: Input, output: Output) {
...
}
}
You don't necessarily need to encode the entire Action
object.
Upvotes: 1