Reputation: 13
I've got a WebSocket that uses an array format of [command, data] to exchange messages. I'm struggling with the Swift Decoder to handle the mixed formats of the data portion. For instance Message #1:
["CFG",{"dimmerDelay":5000,"keyboardShortcuts":true}]
Message #2:
["LFM",true]
I'm using this to decode Message #1
struct Message: Decodable {
let command: String
let config: Config
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
command = try container.decode(String.self)
config = try container.decode(Config.self)
}
}
struct Config: Decodable {
let dimmerDelay: Int
let keyboardShortcuts: Bool
}
What I really want is to split this into a container more like this:
struct Message: Decodable {
let command: String
let data: String
}
Then if the message is of type "CFG" I would pass the data to a decoder that would create the Config object. If the message is of type "LFM" I would check to ensure the result is true and if the message is of another type, I'd pass that data to another decoder that would create the relevant decoded objects.
Upvotes: 1
Views: 59
Reputation: 299703
There are several approaches, but assuming you know all the "command" strings and what they map to, you can take an enum approach:
enum Message {
case config(Config)
case lfm(Bool)
}
To make this Decodable, you just need a switch statement:
extension Message: Decodable {
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
let command = try container.decode(String.self)
switch command {
case "CFG":
self = .config(try container.decode(Config.self))
case "LFM":
self = .lfm(try container.decode(Bool.self))
default:
throw DecodingError.typeMismatch(Message.self,
.init(codingPath: [],
debugDescription: "Unknown command: \(command)"))
}
}
}
After decoding, you'll use a switch statement to determine what you have:
let message = try JSONDecoder().decode(Message.self, from: json)
switch message {
case .config(let config): handleConfig(config)
case .lfm(let bool): handleLFM(bool)
}
Upvotes: 3