Get rid of that hefty NSCoding code..!!!🤗
As we are all aware, to support encoding and decoding of instances in iOS, a class must adopt the NSCoding protocol and implement its methods:
- init(coder:) — Returns an object initialized from data in a given unarchiver.
- encode(with:) — Encodes the receiver using a given archiver.
init(coder:) and encode(with:) must contain the code for each property that needs to be encoded or decoded. 😲
Well, it seems that you have to write so much of redundant code 😖 only with the property name changes. Copy Paste..Copy Paste..!!!😕😴
But why should I do that? 🙇♀️ If the property names are same as the key names and I don’t have any specific requirements, why don’t NSCoding handle everything at its own end? 🤷♀️ Why do I have to write so much code? Noooooo..!!! 😼
OMG..!!! Another problem 🤦♀️. It doesn’t even support structs and enums. 👺 And that means I have to make a class every-time I need to serialize the data, even if I don’t have any class-specific requirement. 🤒
Such a waste of time 🤢. Help me..!!!🙏
Well..well..well..Don’t worry. Apple is here to your rescue again. 🤠
What’s new in Swift 4?
In its Swift 4 release, Apple unveiled a brand new way of data encoding and decoding 🤓 by conforming your custom types with some easy to adopt protocols,
- Encodable — for encoding
- Decodable — for decoding
- Codable — for both encoding as well as decoding
It provides support for class, struct and enum as well. 👌👌
So, let’s see what’s in it for us.
A type that can encode itself to an external representation. It is used by the types that can be encoded.
It contains a single method:
encode(to:) — Encodes this value into the given encoder.
A type that can decode itself from an external representation. It is used by the types that can be decoded.
It also contains a single method:
init(from:) — Creates a new instance by decoding from the given decoder.
A type that can convert itself into and out of an external representation. It is used by the type can be both encoded as well as decoded.
typealias Codable = Decodable & Encodable
It includes the methods declared in both Encodable as well as Decodable.
You’ll learn more about encode(to:) and init(from:) in the upcoming sections 👽.
To encode and decode a custom type, we need to make it Codable.
The simplest way to make a type codable is to declare its properties using types that are already Codable.
- Built-in Codable types — String, Int, Double, Data, URL
- Array, Dictionary, Optional are Codable if they contain Codable types
So, now that we have seen what Codable is, let’s see how to actually use it to encode and decode our own custom types. Here we go..🙂
Encoding — JSONEncoder
You can use JSONEncoder to convert your codable type into Data.
JSONEncoder’s encode(_:) method returns a JSON-encoded representation of the codable type.
Whatttttt…!!! 😱 Just 1 line of code? That’s it? You’re kidding right? There must be something else..some catch..it can’t be..🤯
😂😎 yes this is the only code you need to write to get it working. Isn’t it awesome 👏?. Just 2 simple steps and you are done. No need for that hefty code anymore with so much of overhead. Hi5 ✋.
Like encoding, you can easily get your hands on decoding as well. So what are you waiting for?🤓 Get on with it..🤗
Decoding — JSONDecoder
Just like JSONEncoder, there exist JSONDecoder that can be used to decode your JSON data back into your codable type.
JSONDecoder’s decode(_:from:) method returns a value of the codable type you specify, decoded from a JSON object.
That’s it. That’s how you can encode/decode your Codable Type. Just 2 steps:
- Conform your custom type to Codable protocol.
- Use JSONEncoder/JSONDecoder to encode/decode your custom object.
Choosing Properties to Encode and Decode — CodingKeys
There might be some questions ❓❓coming to your mind,
- What if I want to omit some properties of the Codable Type from the serialization process?
- How to encode/decode if some of the keys 🔑 included in the serialized data doesn’t match the property names of the Codable Type?
Well, Apple provided solution for that too — enum CodingKeys.
Codable types can declare a special nested enumeration named CodingKeys that conforms to the CodingKey protocol. When this enumeration is present, its cases serve as the authoritative list of properties that must be included when instances of a codable type are encoded or decoded.
Things to note about CodingKeys:
- It has a Raw Type — String and conform to CodingKey protocol.
- The names of the enum cases should exactly match 💯 the property names of the Codable Type.
- Answer to 1st Question ✅— Omit the properties from CodingKeys if you want to omit them from encoding/decoding process. A property omitted from CodingKeys needs a default value.
- Answer to 2nd Question ✅ — Raw Value is the thing you need if the property names of Codable Type doesn’t match the keys in the serialized data. Provide alternative keys by specifying String as the raw-value type for the CodingKeys enumeration. The string you use as a raw value for each enumeration case is the key name used during encoding and decoding.
In the below code snippet,
- var format: String = “png” is omitted from the CodingKeys and hence is provided a default value.
- Properties title and url are renamed to name and link using the raw value in CodingKeys — case title = “name” and case url = “link”
Encode and Decode Manually ✏️
There exist scenarios when the structure of your Codable Type differs from the structure of its encoded form, for example:
When you encode a Photo object using the above Photo declaration, the JSON you get looks something like:
What if you don’t want “width” and “height” nested in “size”? 🤔i.e. your JSON should look something like:
In that case, you can provide your own custom logic 📝 of Encodable and Decodable to define your own encoding and decoding logic.
You need to implement encode(to:) and init(from:) methods of Encodable and Decodable protocols explicitly.
Follow the below steps:
- Update the enum CodingKeys to include width and height keys instead of size.
- Remove the conformance to Codable from Photo.
- Create a Photo extension conforming to Encodable and implement encode(to:) method.
- Create a Photo extension conforming to Decodable and implement init(from:) method.
- For now you cannot conform to Codable in an extension 🙅♀️. It might be available in further releases.
Too many yets in this release 🙈. I don’t know why Apple is in so much hurry..🤔
2. You must use a concrete type to encode and decode.
You can get a nice use-case of this scenario here.
Feel free to leave comments if you have any doubts. 🙂🙃