Swift, as a strongly-typed language, gives you a lot of tools in as part of its type system that make development safer and easier — by using full-fledged Swift types, you can make use of those tools to both improve the development experience, and make your code more performant:
A dictionary is an un-typed, general-purpose data structure. This means that:
- The compiler cannot prevent you from making typos when writing out key names, whereas code which refers to a property on a type which does not exist will not compile
- The compiler cannot auto-complete key names for dictionaries like it can for properties on a known type
- Accessing a value inside of a dictionary requires looking up the value, which incurs a performance cost; for properties on a defined type, however, the compiler can generate code which accesses those properties directly
- Accessing a value inside of a
[String: Any]
yields an Optional
value of an unknown type:
- If you know that the value is supposed to be there, the
Optional
is added overhead, mentally and performance-wise
- If you know what type the value is supposed to be, casting it to the type you expect it to be can also be error-prone, and also represents some mental and performance overhead
- Using a dictionary as the primary data store for your data means that every access incurs all of these drawbacks
Using JSONDecoder
(or similar) with a well-defined type gives you the opportunity to validate the incoming data in advance, in one localized spot that may be able to handle failures, or invalid data. It gives you the opportunity to both assert that the individual values are of the right types that you expect (and that they are not missing), but also that the entirety of the data is semantically-meaningful; without performing this validation, you risk either passing invalid data along to a different part of your application (where, combined with all of the above, means that it's very easy to accidentally access the data incorrectly), or, discovering that the data is invalid elsewhere, but not being able to handle the failure from that spot, leading to a very generic error
- This pass also only happens once up-front, meaning that further access to the data incurs no performance cost
In all, except for extraordinarily trivial use-cases, it's highly recommended to use fully fledged types, instead of leaving the untyped data inside of a dictionary.