Topics

#315: Codable Basics 📠

Topics

Swift 4 has brought with it a ton of great improvements. Today we'll cover one of them, it's the new Codable protocol! Codable ships with Swift 4 as part of the Swift standard library and allows us to conform our own types to it to get encoding and decoding functionality "for free".

Encoding and decoding types has never been easier.

Let's dive in!

Before we begin lets back up a second and look at what we're trying to accomplish when it comes to encoding and decoding.

Essentially we want to take an instance of an object or struct and convert (or "encode") it into some other, (usually "machine-readable") format. Then, later, we want to be able to convert (or "decode") the information in that format back into our object or struct.

These days the most common format for encoding/decoding is JSON. It's supported just about everywhere and has the advantage of being both human and machine readable.

For this reason, we'll be discussing JSON in this Bite. It's important to note though, that Codable isn't specific to just JSON. It's built to support encoding and decoding into just about any format we can think of.

In the past, we might have used something like the JSONSerialization class in Foundation to do encode our types into JSON.

This works great, but the encoding input and decoding output was either a Dictionary<String: Any>, or an Array of them. Then we'd need to manually convert to/from our "real" types.

With Codable, we can do much better!

Let's start with a simple struct conforming to Codable:

struct Spaceship : Codable {
  var name: String
}

let ship = Spaceship(name: "Skyhopper")

Now, all we need to do to convert our ship to JSON is:

let data = try? JSONEncoder().encode(ship)

This returns a Data that we can send to a server, store to disk, or do anything else we need with.

Let's convert it to a string real quick so we can take a look at it:

if let string = String(data: data, encoding: .utf8) {
  print(string)
}

This prints:

{"name":"Skyhopper"}

Nice! Notice how we didn't need to specify the names of the "keys" in the JSON, they are inferred from the property names on our struct.

For decoding, we can easily go the other way:

let ship = try? JSONDecoder().decode(Spaceship.self, from: data)

Note how both the .encode and .decode functions can throw and thus we're using the try? keyword to return a nil Optional if encoding or decoding fails.

Before we go let's cover one more nice thing about Codable.

Let's add another struct to the mix:

struct Person : Codable {
  var firstName: String
  var lastName: String
}

struct Spaceship : Codable {
  var name: String
  var pilot: Person
}

Nice. Now when we encode a Spaceship, the system notices that the pilot property's value is also Codable and does the right thing for us automatically:

{"name":"Skyhopper", "pilot":{"firstName":"Luke", "lastName":"Skywalker"}}

That's all for today, next time we'll look at using Codable with more complex types of data likes Dates. Happy coding!