background
Enum types are commonly used in development because they represent different cases of objects. Such as:
enum OrderState: Int {
case new = 1
case payed = 2
case done = 3
}
Copy the code
For enum types whose primitive value is Int, the compiler can automatically synthesize Codable implementations for them.
extension OrderState: Codable {}struct Order: Codable {
let id: Int
let state: OrderState
}
Copy the code
It’s not hard to guess the implementation process for an enum type codable simulation:
- Will be to decode value to Int
- Attempt to construct Int to enum type
extension OrderState: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let int = try container.decode(Int.self)
self = OrderState(rawValue: int) ??...}}Copy the code
However, there is a potential risk in using enum types in Codable. The reason is that OrderState is fixed in the example from the client’s current point of view, whereas the back-end API may iterate in the future and if the value delivered is outside the current declared range, such as case Cancel = 4, the decoder will fail. This corresponds to the possible failure of the construction from Int to OrderState in the above simulated implementation.
Solution: Use struct instead
Enum raw values support codable because they follow the RawReresentable protocol, which provides a default implementation in Codable:
extension RawRepresentable where Self : Decodable.Self.RawValue= =Int {
/// Creates a new instance by decoding from the given decoder, when the
/// type's `RawValue` is `Int`.
///
/// This initializer throws an error if reading from the decoder fails, or
/// if the data read is corrupted or otherwise invalid.
///
/// - Parameter decoder: The decoder to read data from.
public init(from decoder: Decoder) throws
}
Copy the code
With such an implementation, you can use struct to follow RawReprentable to get:
- To avoid case failure, any INT can be delivered
- Replace concrete case declarations with static attributes
Such as:
struct OrderStateStruct: RawRepresentable, Codable {
let rawValue: Int
static let new = OrderStateStruct(rawValue: 1)
static let payed = OrderStateStruct(rawValue: 2)
static let done = OrderStateStruct(rawValue: 3)
}
Copy the code
summary
Swift’s strong typing features stand out in Codable, so take care when designing parameter types. A few caveats:
- A similar scheme can be used for enumeration scenarios where the raw value is string
- In struct mode, Swift can continue to retain the support of Swift case, the difference is that there will be default case, because it is not exhaustive, so in the future when new cases are added, we need to search and supplement in the place where this enumeration is used. There is no compiler support for enum types, so the tradeoff is not too big.
- Considering the use of enum, then we need to consider the decode failure of the bottom of the pocket processing, can be customized to implement Decodable perspective to think and expand.
The resources
Sundel: Codable synthesis for Swift enums
Onevcat: Use Property Wrapper to set default values for Codable decoding