You’ve heard of Codable! It sounds so ‘Swifty’! But what is it?

That was what I was thinking on the train yesterday as I transgressed away from my Functional Programming studies very briefly to check it out. Then something came up at work which meant I could implement some codable code that very day.

Every good solution needs a problem, otherwise you’re just learning for the sake of it…

learn to code ios

The Problem

Imagine you were working on Date-iOS, the dating app for iOS developers. You have just spent several days creating the perfect profile image and bio (similar to how many days you spend creating online avatars in your new MMORPG) and you hit the nice, gradient-friendly ‘Create Profile’ button in the app. The app needs to send data up to the server to be stored and usually we would use JSON for this as it’s very standard nowadays, but the problem is the app stores and understands it’s current user as an ‘AttractiveAndDesirableUser’ class.

Oh this developer was so creative… Anyway, we want to kind of upload an ‘AttractiveAndDesirableUser’ which has a name, age, bio, profile and rating properties. Something like this:


1
2
3
4
5
6
7
class AttractiveAndDesirableUser {
    var name: String
    var age: Int
    var rating: Int
    var profileImageURL: String
    var bio: String
}

So it’s super-simple, but it would be great if we could convert this to JSON as it is without creating a dictionary, then add each property, then serialise it, then upload it?

The Solution

This is where Codable comes in and Swift makes it so nice and ‘Swifty’.

Have you ever noticed that JSONSerialisation encoding takes your data and encodes it into a format suitable for transfer across the web? Well Codable is simply a typealias for encodable and decodable protocols.

Essentially we want our apps to create AttractiveAndDesirableUser’s, encode them into JSON, send them up to the server and then log out, login and download encoded users, decode them into our AttractiveAndDesirableUser class. To do that we are going to start by conforming our well-named class to Encodable like so:


1
2
class AttractiveAndDesirableUser: Encodable {
}

Now when you conform to that protocol, it’s not going to throw you an error even though you haven’t implemented the encode method. Why? Well because all of the types we have so far already conform to Encodable. Types like Int and String already come pre-packaged to handle this. Let’s add a slight change to it to add a dictionary of ‘Desirable Attributes’ that you’re going to allow users to write about themselves on our dating app.


1
2
3
class AttractiveAndDesirableUser {
    var desirableAttributes: [String:Any]
}

These attributes might be ‘Type speed, concentration face, tabs or spaces’… not your usual desirables, but this is for iOS developers, right?

You’ll see the error that’s appeared now in XCode stating that the class doesn’t conform to Encodable. Excellent. If you’ve ever worked with custom UIViews you have to implement a similar method (XCode usually does it for you) so it should look familiar(ish):


1
2
3
4
5
class AttractiveAndDesirableUser {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: )
    }
}

An Encoder has a container property to help us work with it and to encode our cool class we need to provide it with key-value pairs to work with.

ios developer uk

What if our web team changed the expected JSON format to be ‘EpicBIO’ rather than ‘bio’ for our user’s hand-crafted bio? Would we have to re-name the property everywhere in the app? No, you can create an enum that allows us to declare the name of our property to help us:


1
2
3
4
5
class AttractiveAndDesirableUser {
    enum CodeableKeys: String, CodingKey {
        case name, age, rating, profileImageURL, bio, desirableAttributes
    }
}

CodingKey is another protocol we can conform to and it allows the compiler to know we’re going to be using these keys for the encoding. We could change one of these by writing 

1
case bio = "EpicBIO"

 and it would be changed in the JSON for you so it’s super handy. Now let’s finish our implementation:


1
2
3
4
5
6
7
8
9
10
11
class AttractiveAndDesirableUser {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodeableKeys.self)
        try container.encode(name, forKey: CodeableKeys.name)
        try container.encode(age, forKey: .age)
        try container.encode(rating, forKey: .rating)
        try container.encode(profileImageURL, forKey: .profileImageURL)
        try container.encode(bio, forKey: .bio)
        try container.encode(desirableAttributes, forKey: .desirableAttributes)
    }
}

Each one of these attempts to encode can throw an error so we use ‘try’ here but this would go away and create nice JSON for you to send up to the server. Please also note that desirableAttributes would have to make sure it conformed to Encodeable, for example you couldn’t just pass it any old class as the value for the keys, they would have to conform to Encodeable so you may have to repeat some of the steps above for custom classes being passed in.


1
2
3
// TabsOnlyUser is an instance of 'AttractiveAndDesirableUser'
let data = JSONSerialization.data(withJSONObject: TabsOnlyUser, options: .prettyPrinted)
}

You see we can just pass in our AttractiveAndDesirable user straight to the JSONSerialisation process now thanks to Swift’s Encodable! We haven’t covered decoding in this blog, but we covered the CodingKeys enum, encodable and talked about decodable and codeable.