We will use the sample json mentioned below to explain
Playground file is attached to test the below mentioned examples.
let urlString = "https://jsonplaceholder.typicode.com/todos/1"
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
Codable
What’s encoding and decoding in simple terms in the context.
Decoding : We need to convert JSON response to the objects defined in our projectt
Encoding : We need to convert our custom objects into JSON string to post to a service.
JSON serialization before swift 4 :
A verbose process , length depending on the size of the json structure.
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let data = json as? [String: Any] {
//This expands to every property in the struct
if let userId = data[“userId”] as? Int {bookCatalog.userId = userId }
}
Starting Swift 4:
JSON serialization encoding and decoding can be achieved with mere adopting to Codable protocol.
The Codable protocol is a composition of two protocols, Decodable and Encodable.
Once can define the struct in the following ways depending on your use case
if you intend to decode and encode for your use case
Struct BookCatalog : Codable {…}
You can also simply use if your use case is only to decode the response and use the data in your UI.
Struct BookCatalog : Decodable {…}
Decodable and Encodable protocols are adopted by the components that encode/decode various data formats, like JSON.
For our discussion we have
The JSONDecoder and JSONEncoder classes use those the Decoder and Encoder protocols to provide the functionality to decode/encode JSON.
Example to encode /decode using codable
struct BookCatalog: Codable {
let userId: Int
let id: Int
let title: String
let completed: Bool
let test:String?
}
func fetchData() {
if let url = URL(string: urlString) {
let dataTask = URLSession.shared.dataTask(with: url) { data, response, error in
if let jsonData = data {
let decoder = JSONDecoder()
do {
//Below 1 line does the magic to convert json to required Objects when you are adopting to codable protocol
let catalog = try decoder.decode(BookCatalog.self, from: jsonData)
print(catalog.userId)
print(catalog.id)
print(catalog.title)
print(catalog.completed)
let encoder = JSONEncoder()
do {
let encodedJson = try encoder.encode(catalog)
//Below 1 line does the magic to convert Object to JSON string when you are adopting to codable protocol
if let jsonString = String(data: encodedJson, encoding: .utf8) {
print(jsonString)
}
} catch {
print("Encode failed")
}
} catch {
print("Decode failed")
}
}
}
dataTask.resume()
}
}
Coding keys
When do you need coding keys ??
If you want a custom name for your properties than what’s in json response .Every class or struct that conforms to Codable can declare a special nested enumeration called CodingKeys. You use it to define properties that should be encoded and decoded, including their names.
Below is the example to define your structure with coding keys.
struct BookCatalogKeys: Codable {
let userIdentifier: Int
let index: Int
let title: String
let completed: Bool
enum CodingKeys: String, CodingKey {
case userIdentifier = "userId"
case index = "id"
case title
case completed
}
}
Serialization code remains the same even though we change the property names using coding keys.
func fetchDataKeys() {
if let url = URL(string: urlString) {
let dataTask = URLSession.shared.dataTask(with: url) { data, response, error in
if let jsonData = data {
let decoder = JSONDecoder()
do {
let catalog = try decoder.decode(BookCatalogKeys.self, from: jsonData)
print(catalog.userIdentifier)
print(catalog.index)
print(catalog.title)
print(catalog.completed)
let encoder = JSONEncoder()
do {
let encodedJson = try encoder.encode(catalog)
if let jsonString = String(data: encodedJson, encoding: .utf8) {
print(jsonString)
}
} catch {
print("Encode failed")
}
} catch {
print("Decode failed")
}
}
}
dataTask.resume()
}
}
What’s if a key value pair in nil
If your json response doesn’t always send all the key value pairs, you can define your property as optional to avoid decode failures. Example code below
struct BookCatalog: Codable {
let userId: Int
let id: Int
let title: String
let completed: Bool //
let test:String? // you can make this non optional to see the decoder fail as this “test” key value pair is not available in the response.
}
What’s if we don’t need all the values from the json
you can always define a smaller structure as needed. The below code would work just fine.
struct BookCatalog: Codable {
let userId: Int
let id: Int
}



