I am loading in JSON which has integers that I wish to map to an enum
//Some JSON object
{
"id": "....",
"name": "Some Locomotive"
"livery": 1,
"generation": 1
// other variables
}
I can load this JSON in using:
struct Locomotive: Codable {
var id, name: String
var generation: Int
// var livery: Int -- Replace this with my own enum (below)
var livery: Livery?
private enum CodingKeys: CodingKey {
case id, name, generation
case livery = "livery" // complains of raw value issue
}
}
Currently both the generaiton and livery are just Integers; but to make coding easier for me I wish to use map the livery Integer to an enum; so rather than remembering 1 = green, etc; I can just say .green
But I am have trouble mapping the key livery to my enum.
Enum case cannot have a raw value if the enum does not have a raw type
But I'm sure it does; I've defined the raw value in the enum as private though;
enum Livery : Codable {
case green, red, blue, yellow
}
extension Livery {
private enum RawValue: Int, Codable, CaseIterable {
case green = 1, red, yellow, blue
}
private enum CodingKeys: Int, CodingKey {
case green, red, blue, yellow
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let key = container.allKeys.first
switch key {
case .green:
self = .green
case .red:
self = .red
case .yellow:
self = .yellow
case .blue:
self = .blue
default:
throw DecodingError.dataCorrupted(
DecodingError.Context(
codingPath: container.codingPath,
debugDescription: "Error -- Unabled to decode."
)
)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .green:
try container.encode(RawValue.green)
case .red:
try container.encode(RawValue.red)
case .yellow:
try container.encode(RawValue.yellow)
case .blue:
try container.encode(RawValue.blue)
}
}
}
The above enum decodes the raw value and encodes it.
However, I am unable to map the Livery in the parent struct to this enum and I'm wondering how I can do this?
...
I think I have to implement init(from decoder: Decoder)
and encode(to encoder: Encoder)
to this structure too -- especially if I want to save my data to JSON in the future; but I am not sure.
Thus, my query is - how do you map an Integer provided by the JSON to a custom enum for both saving (encoding) and loading (decoding).
With thanks
You can simplify your code quite a lot, all you need is the below code. By saying that your enum is of type Int swift can synthesise the correct decoding code
struct Locomotive: Codable {
var id, name: String
var generation: Int
var livery: Livery?
}
enum Livery: Int, Codable {
case green = 1, red, blue, yellow
}