Suppose there is a json map whose key is String
that converted from Int
, such as "1"
. How can I declare a Swift enum whose rawValue
is Int
to match its key?
In the code listed below, if the key of map
in ModelA
is String
, then the model
will be deserialized correctly.
But if I replace String
with EnumA
, EnumB
, EnumC
or EnumD
, the model
will be nil
at last.
struct ModelA: Codable {
let pan: String
let map: [String: ModelB] // Try to replace string with a swift enum.
enum CodingKeys: String, CodingKey {
case pan, map
}
}
struct ModelB: Codable {
let pan: String
enum CodingKeys: String, CodingKey {
case pan
}
}
enum EnumA: Int, Codable {
case a = 1
case b = 2
}
enum EnumB: String, Codable {
case a = "1"
case b = "2"
}
enum EnumC: Int, Codable {
case a = 1
case b = 2
enum CodingKeys: String, CodingKey {
case a = "1", b = "2"
}
}
enum EnumD: Int, Codable {
case a = 1, b = 2
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let status = try? container.decode(String.self)
switch status {
case "1":
self = .a
case "2":
self = .b
default:
throw DecodingError.typeMismatch(EnumD.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "??????", underlyingError: nil))
}
}
}
extension String {
func toModel<Model: Decodable>(_ type: Model.Type) -> Model? {
guard
let data = data(using: .utf8)
else {
return nil
}
let decoder = JSONDecoder()
return try? decoder.decode(Model.self, from: data)
}
}
let str2 = """
{"pan": "234", "map":{"1":{"pan": "aaa"}}}
"""
let model = str2.toModel(ModelA.self)
print(model)