Hi! This post has moved to a new blog! Come to fivestars.blog for the latest articles!
If you haven’t seen it already, I suggest you to watch the related WWDC session (the
Codablepart starts past 23 minutes).
In short: you can now convert a set of data from a JSON Object or Property List to an equivalent
Class, basically without writing a single line of code.
Here’s an example (it’s a Swift Playground!):
What the Compiler Does Without Us Noticing
If we look at the
Decodable documentation, we see that the protocol requires the implementation of a
init(from: Decoder) method.
We didn’t implemented it in the Playground: why did it work?
It’s for the same reason why we don’t have to implement a
Swifter initializer, but we can still go ahead and initialize our struct: the Swift compiler provides one for us! 🙌
All of the above is great and just works™ as long as all we need to parse is a subsets of primitives (strings, numbers, bools, etc) or other structures that conform to the
But what about parsing more “complex structures”?
Well, in this case we have to do some work.
Implementing init(from: Decoder)
⚠️ This part might be a bit trickier to understand: everything will be clear with the examples below!
Before diving into our own implementation of this initializer, let’s take a look at the main players:
As the name implies, the
Decoder transforms something into something else: in our case this means moving from a native format (e.g. JSON) into an in-memory representation.
We will focus on two of the
In both cases, the
Decoder returns a (Data) Container.
Now you know what’s up with all these container pictures! 😜
The second function tells the decoder that there’s no key: the returned container,
SingleValueDecodingContainer, is actually the data that we want!
Thanks to our
Decoder we’ve moved from a raw native format to a structure that we can play with (our containers). Time to extract our data! Let’s take a look at the two containers that we’ve just discovered:
In this case we know that our container is keyed, you can think of this container as a dictionary
Different keys can hold different types of data: which is why the container offers several
This method is where the magic happens: by calling it, the container returns us our data’s value of the given type for the given key (examples below!).
Most importantly, the container offers the generic method
decode<T>(T.Type, forKey: K) throws -> T where T: Decodablewhich means that any type, as long as it conforms to
Decodable, can be used with this function! 🎉🎉
Everything works as above, just without any keys.
We’ve seen all the players that will help us go from data stored in our disk to data that we can use in our App: let’s put them all together!
Take the playground at the start of the article for example: instead of letting the compiler doing it for us, let’s implement our own
Step 1: Choosing The Right Decoder
⚠️ JSON and P-list encoders and decoders are embedded in the Swift Library: you can write your own coders to support different formats!
Step 2: Determining The Right Container
In our case the data is keyed:
"Federico Zanetello" we must ask for the value of key
"fullName", to reach
123456 we must ask for the valued of index
Therefore, we must use a
KeyedDecodingContainer Container (by calling the
Now that we have our keys set up, we can go on and create our container:
Step 3: Extracting Our Data
Finally, we must convert the container’s data into something that we can use in our app:
Step 4: Initializing our Struct/Class
We can use the default
Voila! We’ve just implemented
Decodable all by ourselves! 👏🏻👏🏻
Here’s the final playground:
Going further (More Playgrounds!)
Now that our
Swifter struct conforms to
Decodable, any other struct/class/etc that contains such data can automatically decode
Swifter for free. For example:
More Complex Structs
And so on!
In all probability, during your first
Decodable implementations, something will go wrong: maybe it’s a key mismatch, maybe it’s a type mismatch, etc.
To detect all of these errors early, I suggest you to use Swift Playgrounds with error handling as much as possible:
Even on the first Xcode 9 beta, the error messages are clear and on point 💯.
I was really looking forward to this new Swift 4 feature and I’m very happy with its implementation. Time to drop all those custom JSON parsers!
That’s all for today! Happy Decoding!
Federico is a Bangkok-based Software Engineer with a strong passion for Swift, Minimalism, Design, and iOS Development.