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)
}

swift-codable-json-data-encode

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.

By admin

Leave a Reply

%d bloggers like this: