Encoding and Decoding
Converting your instances to another representation, like a string or a stream of bytes. This process is known as encoding, also known as serialization.
The reverse process of turning the data into an instance is called decoding, or deserialization.
Imagine you have an instance you want to write to a file. The instance itself cannot be written as-is to the file, so you need to encode it into another representation, like as a stream of bytes:
Once the data is encoded and saved to a file, you can turn it back into an instance whenever you want by using a decoder:
Automatic Encoding and Decoding
If you want your type to be codable, the simplest way to do it is by conforming to Codable and making sure all its stored properties are also codable.
struct Employee: Codable {
var name: String
var id: Int
}
Encoding and Decoding Custom Types
JSON stands for JavaScript Object Notation, and is one of the most popular ways to serialize data. It’s easily readable by humans and easy for computers to parse and generate.
JSONEncoder and JSONDecoder
do {
// Encode object to data
let jsonEncoder = JSONEncoder()
let jsonData = try jsonEncoder.encode(employee1)
// Convert json data to string
let jsonStr = String(data: jsonData, encoding: .utf8)
// Decode data to object
let jsonDecoder = JSONDecoder()
let employee2 = try jsonDecoder.decode(Employee.self, from: jsonData)
} catch {
debugPrint(error.localizedDescription)
}
Note that you need to tell the decoder what type to decode the JSON to, because the compiler can’t figure this out on its own.
Renaming Properties With CodingKeys
CodingKey Protocol, CodingKeys Enum
The CodingKeys enum, which conforms to CodingKey protocol, lets you rename specific properties in case the serialized format doesn’t match the requirements of the API.
struct Employee: Codable {
var name: String
var id: Int
var favoriteToy: Toy
enum CodingKeys: String, CodingKey {
case id = "employeeId"
case name
case favoriteToy
}
}
There are several things to note here:
- CodingKeys is a nested enumeration in your type.
- It has to conform to CodingKey.
- You also need String as the raw type, since the keys are always strings.
- You have to include all properties in the enumeration, even if you don’t plan to rename them.
- By default, this enumeration is created by the compiler, but when you need to rename a key you need to implement it yourself.
Manual Encoding and Decoding
extension Employee {
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
id = try values.decode(Int.self, forKey: .id)
let gift = try values.decode(String.self, forKey: .gift)
favoriteToy = Toy(name: gift)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(id, forKey: .id)
try container.encode(favoriteToy.name, forKey: .gift)
}
}