I have defined an enum
as follows:
enum Type: String, Codable {
case text = "text"
case image = "image"
case document = "document"
case profile = "profile"
case sign = "sign"
case inputDate = "input_date"
case inputText = "input_text"
case inputNumber = "input_number"
case inputOption = "input_option"
case unknown
}
that maps a JSON string property. The automatic serialization and deserialization works fine, but I found that if a different string is encountered, the deserialization fails.
Is it possible to define an unknown
case that maps any other available case?
This can be very useful, since this data comes from a RESTFul API that, maybe, can change in the future.
You can extend your Codable
Type and assign a default value in case of failure:
enum Type: String {
case text,
image,
document,
profile,
sign,
inputDate = "input_date",
inputText = "input_text" ,
inputNumber = "input_number",
inputOption = "input_option",
unknown
}
extension Type: Codable {
public init(from decoder: Decoder) throws {
self = try Type(rawValue: decoder.singleValueContainer().decode(RawValue.self)) ?? .unknown
}
}
edit/update:
Xcode 11.2 • Swift 5.1 or later
Create a protocol that defaults to last case of a CaseIterable & Decodable
enumeration:
protocol CaseIterableDefaultsLast: Decodable & CaseIterable & RawRepresentable
where RawValue: Decodable, AllCases: BidirectionalCollection { }
extension CaseIterableDefaultsLast {
init(from decoder: Decoder) throws {
self = try Self(rawValue: decoder.singleValueContainer().decode(RawValue.self)) ?? Self.allCases.last!
}
}
Playground testing:
enum Type: String, CaseIterableDefaultsLast {
case text, image, document, profile, sign, inputDate = "input_date", inputText = "input_text" , inputNumber = "input_number", inputOption = "input_option", unknown
}
let types = try! JSONDecoder().decode([Type].self , from: Data(#"["text","image","sound"]"#.utf8)) // [text, image, unknown]