Even though they are sometimes overused, enums are still a great tool. Thanks to
Codable they can easily be decoded from JSON sent by your backend.
This is great until you need to add a new case to the enum. Then you have to either deal with versioning your API or you need to tell your users to update the app. In some cases you have no choice, but in other cases it would be fine to just ignore the new value and fall back to some default behavior.
Here are a few ways I used to realize such a scenario:
The simplest way would be to replace enums with a
In code this can be used just like an enum would, you’d only have to add a
default case to every switch statement.
This can lead to situations where a different subset of those cases is handled in different places. Sometimes that’s fine, but in other cases you want to ensure to handle all known cases everywhere. So you need an actual enum in order for the compiler to be able to do exhaustiveness checks.
Enum with “Unknown” case
To do this we simply can manually implement the decoding and map unknown values to a default case:
Implementing this for many enums becomes pretty boring. Luckily we can share the implementation between all enums by writing a protocol with a default implementation:
Using this we can define our enum like we would normally and get that behavior for free by just conforming to the
UnknownDecodable protocol. Note that our enum case
unknown can fulfill the protocol requirement of
static var unknown: Self:
Decoding unknown cases as
A final solution I sometimes find useful is decoding the enum as optional and mapping unknown values to
This is easy to do if we manually implement decoding for the struct that contains this enum. But this would lead to a lot of (possibly repeated) boilerplate code we don’t like to write. Instead we can use a property wrapper:
The extension on
KeyedDecodingContainer is necessary to handle missing or
null values in the JSON.
When to use which
I choose the
RawRepresentable struct when I don’t need to make a decision based on that value. This could be for looking up some resource or other values in a dictionary.
DecodeUnknownAsNil property wrapper is great if the enum value is optional anyways and you can handle the unknown case just as if there was no value at all.
For most cases I would chose the
UnknownDecodable protocol though. If I make my property optional I can distinguish between no value and an unknown value. And if the property is not optional I know the decoding will fail so I can catch bugs on the server side where required properties are missing.