Recently, I began work on a new iOS app and had to work with
Codable, the new protocol introduced in Swift 4 that makes converting between Swift types and JSON data incredibly easy. However, Codable has some limitations and issues I had to work around.
While by default Codable supports most common Swift types, including strings, arrays, number types and more, out of the box, it does not support some platform specific types. For example, if you try to use a UIColor or UIImage, you’ll get an error telling you that your
Type does not conform to protocol 'Decodable'.
In this blog post, I’ll explain how to use UIImage or UIColor together with Codable, so that you can load a custom theme or images from your server.
If you’re reading this blog post, I’m going to assume you are already familiar with using Codable and how it works. If you aren’t, I’d strongly recommend that you go and read Paul’s great blog post about it, then come back to this.
Here is a short example, with an array of Blog objects in JSON and a corresponding Swift struct:
The above example could be decoded like this:
⚠️ Note: If your JSON is inside a String, you need to convert it to a
Dataobject like this:
Codable is great for easy JSON conversion without the need for third parties or complicated custom decoding code, but if we try to have a variable containing a UIColor, we’ll receive a strange error:
By default, Codable automatically adds support for JSON encoding and decoding when we conform to it. However, since
UIColor does not implement the
Encodable) protocol, Codable isn’t able to let our object be encoded/decoded, because it would fail to support one of the properties.
Although it isn’t supported automatically, there are a few ways to resolve this, the best one being using a wrapper class like this:
We can then use the
uiColor computed variable for labels, controls, and other things which need a UIColor.
An example JSON to use together with our wrapper class would look something like this:
If you wanted to, you could add support for hex colors to UIColor with a custom init, then use those in your JSON to make it shorter and simpler.
As with colors, Codable also doesn’t support decoding or encoding UIImages. Although we could do something similar to what we did with colors and just use the image data, it would be better if we supported loading images from a URL, because JSONs aren’t great to store any type of raw data.
First, we’ll add a custom extension to
UIImage to allow us to load images from a URL. UIImage already supports loading from data and we can load data from a URL, but by using a custom initializer like this we can do all the hard work of using threads and safely loading the image in one place. We’ll also use the new Result type in Swift 5 for a cleaner implementation.
Next, we can create a special UIImage wrapper, like the one we used before for UIColor:
However, this will give us the same error as we used to get without the wrapper class! Because we want to support loading images from URLs, we’ll have to use a custom Codable implementation.
To support URLs as well as later on encoding into images (so we can cache them to disk), we’ll need a custom
CodingKeys enum (we’re explicitly setting the
image case’s string value to
uiImage to match our variable’s name):
Now, we can add the custom decoder implementation:
We’re just telling the decoder we want to use our custom CodingKeys. Then, we ask it to decode a URL from the JSON and use it to load and set the image.
As you can see, we also support decoding from image data. This is so that we can also support encoding our custom wrapper class and saving it to disk, with a custom encoder like this:
However, do note that this is not recommended for most apps as it is usually best to save images as files and load them from their file URL.
In this tutorial, we explored how to add support for Codable to 2 types that don’t normally support it, so you can now use images or colors in your JSON with ease. This technique can be applied to any Swift type that doesn’t support Codable, by using the same kind of wrapper class and format.
I hope this tutorial helped you out if you were trying to use colors or images in your JSON, or taught you a new trick you might find useful in the future. If you have any questions or feedback, feel free to send them or email me. Also, make sure to subscribe to my weekly newsletter below so you don’t miss a single post!
Thanks for reading 😊