Reputation: 117
I am trying to make my enumeration that has different associated values comply to the Decodable protocol, but am having trouble with the associated values part.
enum SportType: Decodable {
case team(String, String) //Two team names
case individual([String]) //List of player names
}
I have successfully gotten an enum to conform to Decodable without associated values, but am having trouble doing the same thing with the associated values.
//Works but no associated values
enum SportType: String, Decodable {
case team, case individual
}
Upvotes: 3
Views: 963
Reputation: 14004
You need to create a custom init(from decoder: Decoder) throws
, and treat your associated values like they are normal fields in the object, using CodingKeys
to decode them. Details depend on how your associated values are actually represented in encoded object.
For example if your values are encoded as:
{ "team1": "aaa", "team2": "bbb" }
and
{ "individual": ["x", "y", "z"]}
You can:
enum SportType: Decodable {
case team(String, String) //Two team names
case individual([String]) //List of player names
// Define associated values as keys
enum CodingKeys: String, CodingKey {
case team1
case team2
case individual
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
// Try to decode as team
if let team1 = try container.decodeIfPresent(String.self, forKey: .team1),
let team2 = try container.decodeIfPresent(String.self, forKey: .team2) {
self = .team(team1, team2)
return
}
// Try to decode as individual
if let individual = try container.decodeIfPresent([String].self, forKey: .individual) {
self = .individual(individual)
return
}
// No luck
throw DecodingError.dataCorruptedError(forKey: .individual, in: container, debugDescription: "No match")
}
}
Test:
let encoded = """
{ "team1": "aaa", "team2": "bbb" }
""".data(using: .utf8)
let decoded = try? JSONDecoder().decode(SportType.self, from: encoded!)
switch decoded {
case .team(let a, let b):
print("I am a valid team with team1=\(a), team2=\(b)")
case .individual(let a):
print("I am a valid individual with individual=\(a)")
default:
print("I was not parsed :(")
}
Prints:
I am a valid team with team1=aaa, team2=bbb
Upvotes: 3