Swift Codable: tips and tricks
Let’s dive into Codable to see what are the benefits of migrating from your third-party json library.
What is Codable?
If you take a look into the
Codable definition you’ll find out that it’s just a way to tell that something is
Making your custom types conform these protocols will allow you to represent them in different forms such as JSON or property list (Plist).
Some of you may know
NSCodingthat does something very similar, the difference is that encoding something with NSCoding will produce a Data (NSData) that is basically a buffer of bytes.
Why is it a game changer?
Today every App is connected with web services and most of them provide data using the JSON format for its ease of reading and generating for both humans and machines.
In order to manage JSON data, the client has to “translate” it in objects that can be easily manipulated (eg: structs or classes); this process is called “parsing” and the part of the app that does the job is the parser.
By implementing the Codable protocol in your data model you can forget about parses because your objects will be automatically translated from/to JSONs.
Suppose we want to know some basic information about this post and the Medium API give us something like this:
Then our model will probably look like this
The only thing to do now is make our Post struct conforms Decodable protocol and use a
That’s pretty straightforward right?
What’s happening is that the decoder is mapping the json’s fields with the Post object’s properties that have the exaclty same names.
In order to map object’s properties with json’s field that have different names we need to tell the decoder where to go searching. We can do that with a simple enum named CodingKeys that conforms CodingKey where the raw values of the cases match the json properties names.
One important thing to notice is that the name of the enum must be CodingKeys, if we want to change is we need to provide a custom init.
Beside the CusomJsonKeys enum that’s is pretty self-explanatory one thing to notice is that in this case we need to provide an
init(from decoder: Decorer)throw.
In this method we provide the decoder with our custom keys in order to get a container that is an instance of
KeyedDecodingContainer. You can think the container as some kind of dictionary.
We can agree that the syntax is a little bit messy and not very readable but I’ve done this extension to make things easier.
By adding this extension you will be able to use the KeyedDecodingContainer just as you would do with a dictionary.
Now we also don’t need to tell the property type because it will be inherited. Neat.
Nothing changes with nested object, the only think you need to remember is that even the nested objects need to conform the
Decodable protocol and need to provide a custom init where needed.
Flatten nested objects
When we have a nested JSON but we want to flatten it into one single object we could use the function
Sometimes we don’t want to have fixed values for our coding keys but we want to be able to build them at run time. This is possible using a concrete implementation of the protocol
ConcreteCodingKeys it is possible to use any run time string as coding key like that:
something = try container.decode(String.self, forKey: GenericCodingKeys(stringLiteral: "aDynamicKey\(3+4)")
This technique is useful when, for example, when you want to flatten multiple properties into a single array like in the following example.
To infinity and beyond
- “Automatching” is only available with type values such as struct, if you want your class to work with
Codableyou have to always provide a custom init.
- You can decode array and dictionary as well, just use
decoderContainer.decode([YourObjectInAnArray].self, from: jsonData)for array and
decoderContainer.decode([YourKey: YourObjectInArray].self, from: jsonData)for dictionaries.
- If you need a custom coder in addiction to
PropertyListCoderyou can write your own!
You can download here a playground where you can find a lot of examples of decoding simple and complex objects.
Using Codable instead of a third-party library (such as Marshal or SwiftyJSON) could look tricky at the beginning but after a some pratice you’ll able to achieve anything you want with (usually) less code and since you’re using a part of the standard SDK your app will weight less.