In this tutorial, we’ll be discussing the Codable Protocol and its forms in order to parse/serialize JSON in our Swift Playground. We have previously discussed Swift JSON parsing using JSONSerialization
.
Swift Codable Protocol
Codable Protocol was introduced in Swift4 and is a nice replacement for NSCoding.
Let’s review NSCoding once.
Swift NSCoding
NSCoding protocol which is a part of the foundation framework has been there for the same purpose i.e. encoding and decoding data to/from JSON respectively.
Let’s use NSCoding in our XCode Playground.
class Student : NSObject, NSCoding
{
var name: String?
var age: Int?
required init?(coder aDecoder: NSCoder)
{
//Returns an object initialized from data in a provided unarchiver.
self.name = aDecoder.decodeObject(forKey: "name") as? String
self.age = aDecoder.decodeObject(forKey: "age") as? Int
}
init(name:String,age:Int) {
self.name = name
self.age = age
}
func encode(with aCoder: NSCoder)
{
//Encodes the given object using provided archiver.
aCoder.encode(self.name, forKey: "name")
aCoder.encode(self.age, forKey: "age")
}
override var description: String {
get {
return "[ name=(self.name) ; age=(self.age) ]"
}
}
}
encode
along with the decoder init function must be implemented since we’ve used the NSCoding Protocol.
For serialization we use the class NSKeyedArchiver:
let student = Student(name: "Anupam", age: 24)
let data = NSKeyedArchiver.archivedData(withRootObject: student)
let decoded = NSKeyedUnarchiver.unarchiveObject(with: data) as! Student
print(decoded)
//Prints [ name=Optional("Anupam") ; age=Optional(24) ]
Try changing the key name in any of the function and you’ll see a nil returned.
NSCoding is useful for saving the application state by saving the object graph in the Archiver.
Having said that, NSCoding has its disadvantages too:
- Cannot be used with anything else except Classes in Swift.
- Too much redundant code for encoding and decoding. Need to add for each field.
Apple recognized these drawbacks and brought in the Codable Protocol for swifter development!
Codable Protocol is the amalgamation of two protocols: encodable
and decodable
.
Codable is a typealias:
typealias Codable = Encodable & Decodable
These protocols work with the Swift class, struct, enums.
Another protocol CodingKey is used to defined our own custom keys.
We can omit certain values by assigning default values to them.
Encodable protocol encodes the custom type into a data. The data can be a plist or a JSON.
Encodable uses the encode(to: )
function.
Decodable coverts the data back to the custom type.
Decodable uses the init(from: )
function.
JSONEncoder and JSONDecoder are used for JSON data
PropertyListEncoder and PropertyListDecoder are used for plist data.
Encoding and Decoding JSON Data
enum Section: String, Codable
{
case A
case B
case C
}
class Student: NSObject, Codable
{
var name: String = ""
var id: URL? = nil
var year: Int = 0
var isNew:Bool = true
var peer: [String:String]? = nil
var section: Section = .A
}
let student = Student()
student.name = "Anupam"
student.year = 2011
student.id = URL(string: "https://www.journaldev.com")
student.section = .B
let encodedObject = try? JSONEncoder().encode(student)
if let encodedObjectJsonString = String(data: encodedObject!, encoding: .utf8)
{
print(encodedObjectJsonString)
}
To Decode a JSON string we do:
let jsonString = """
{
"name":"Anupam",
"isNew":true,
"year":2018,
"id":"j.com",
"section":"A"
}
"""
if let jsonData = jsonString.data(using: .utf8)
{
let studentObject = try? JSONDecoder().decode(Student.self, from: jsonData)
}
Decoding a JSON Array
let jsonString = """
[{
"name":"Anupam",
"isNew":true,
"year":2018,
"id":"j.com",
"section":"A"
},
{
"name":"Anupam",
"isNew":true,
"year":2011,
"id":"j.com",
"section":"C"
}]
"""
if let jsonData = jsonString.data(using: .utf8)
{
let studentObject = try? JSONDecoder().decode([Student].self, from: jsonData)
print(studentObject?.count)
}
If the json string that is passed to the decoder doesn’t have all the properties, it will return a nil instance.
Nested Data
Removing unnecessary properties
Using the CodingKey protocol we can decide which properties we want to encode or decode.
enum Section: String, Codable
{
case A
case B
case C
}
class Student: NSObject, Codable
{
var name: String = ""
var id: URL? = nil
var year: Int = 0
var isNew:Bool = true
var peer: [String:String]? = nil
var section: Section = .A
enum CodingKeys:String,CodingKey
{
case name
case id
}
}
let student = Student()
student.name = "Anupam"
student.year = 2011
student.id = URL(string: "https://www.journaldev.com")
student.section = .B
Output:
{"name":"Anupam","id":"https://www.journaldev.com"}
Only the cases passed are encoded.
Using custom key names
Again the CodingKey protocol is used to assign custom key names to the properties that will be encoded and decoded.
enum Section: String, Codable
{
case A
case B
case C
}
class Student: NSObject, Codable
{
var name: String = ""
var id: URL? = nil
var year: Int = 0
var isNew:Bool = true
var peer: [String:String]? = nil
var section: Section = .A
enum CodingKeys: String, CodingKey {
case name = "user_name"
case id = "user_id"
case year
case isNew = "is_new"
case peer
case section
}
}
Output:
This brings an end to this tutorial on Swift Codable Protocol. It’s used often in JSON Parsing in iOS Applications.