Swift and JSON — Introducing the Codable Protocol
Ashok’s Bite Sized Guides — Guide #01
JSON has become the lingua franca of data transfer across the World Wide Web. In this bite sized guide, we will introduce Swift’s Codable Protocol for encoding and decoding JSON.
Conforming to the Codable
Protocol is straightforward:
- Basic types like STRING, DOUBLE, INT, DATE, DATA or URL automatically conform to
Codable
- Any type whose properties are
Codable
automatically conforms toCodable
just by declaring conformance to the protocol:
struct Coordinate: Codable {
var latitude: Double
var longitude: Double
}
- Built-in types such as ARRAY, DICTIONARY, and OPTIONAL also conform to
Codable
whenever they contain codable types - Indeed, any custom type can also be
Codable
as long as all of its properties areCodable
struct Landmark: Codable {
var name: String
var foundingYear: Int
var location: [Coordinate]
}
Once we established the Codable
protocol for our types, we can readily encode and decode Swift types to JSON.
Encoding Swift Objects to JSON
Encoding is the easy part. Here is a generic function you can use.
func myEncoder<T: Encodable>(_ data: T) throws -> String { let encoder = JSONEncoder() encoder.keyEncodingStrategy = .convertToSnakeCase let jsonData = try encoder.encode(data) return String(data: jsonData, encoding: .utf8)!}
Note that Codable
is a typealias for the Encodable
and Decodable
protocols. In the above function, we just need the parameter data to conform to the Encodable
protocol (which Codable
will also do).
Decoding Swift Objects to JSON
Decoding objects can be just as easy as encoding, but we also have a few extra options to better handle external data being passed into our programs. Antoine van der Lee covers them well in this post.
Lets run through some basic concepts first:
- Unless you use custom coding keys (refer to the official Apple Documentation), your property names need to match exactly to the keys supplied in the JSON string you are decoding
- This makes sense given Swift would not know how to otherwise guess how to map JSON data to Swift Objects
- As JavaScript is typically written in snake_case whilst Swift is written in camelCase, it is very valuable to set the
keyEncodingStrategy
andkeyDecodingStrategy
to.convertToSnakeCase
(see above in myEncoder) or.convertFromSnakeCase
(see below in myDecoder) - Any keys in the JSON string that are not defined as properties in your Swift types simply get discarded. This is helpful in that you can update your APIs on the server side without breaking the client code already installed on your users devices (and subsequently requiring an app update to fix).
With all that said, below is an example of a decoder function — it is not too scary! [Actually it does some nice things with protocols and generics, but that’s not related to decoding JSON :)]
func myDecoder<T: Decodable>(_ decodeType: T.Type, _ from: String) throws -> T { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase let jsonData = from.data(using: .utf8)! return try decoder.decode(decodeType, from: jsonData)}
Thanks for reading!