DEV Community

Cover image for Handle varying DataType in Codable
NalineeR
NalineeR

Posted on • Edited on

Handle varying DataType in Codable

Codable is a type alias for the Encodable and Decodable protocols. These protocols are used for encoding and decoding.

While decoding we often face a situation where the data type may change in response coming from Backend. Let's see how we can handle the case -

Scenario - We will be loading Employee data from a json file.

Step 1 - Let’s take a UILable for showing employees’ name and create an IBOutlet for it.

Image description

Step 2 - I have added an Employees’ json for demo purpose

Image description

Step 3 - Let’s create a file for Modal and create a codable struct for our Employees data

Image description

Step 4 - Our function loadDataFromJson(handler:@escaping((Data)->())) reads the json from Bundle and convert it’s content to Data. In the end it calls the handler with that data.

Step 5 - Now we parse the data into the Employees modal in the function func parseDataToEmployee(). After parsing to modal, we set Employees’ name and id on our label lblEmployee.

Below is how the ViewController file looks in the end.
Image description

Now run the project. Here comes the main part.
You get and error which says - "Expected to decode Int but found a string/data instead.", underlyingError: nil))”

This is coming because our Employee modal is expecting the id to be an Int but in JSON it is getting String somewhere.
You can check in the Employee.json that first object has id as String whereas all the other objects have it as Int.

Let’s check how to handle this case where the data type may vary.

The Codable protocol provides us an init function. We need to use this to handle our error. So let’s go to our Modal file and add the init function as follow -

init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)

        if let intId = try? container.decode(Int.self, forKey: .id){
            //if received as int then parse as is
            id = intId
        }else if let strId = try? container.decode(String.self, forKey: .id){
            //if received as String then convert to Int and set
            id = Int(strId) ?? 0
        }else{
            id = 0
        }
        employeeName = try container.decode(String.self, forKey: .employeeName) 
    }
Enter fullscreen mode Exit fullscreen mode

In the above init function we are using if else condition based on the received data type.
Now run the project one more and see the employee data is parsed with no error.
This is how it looks -

Image description

Project Link - https://github.com/NalineeR/CodableInitDemo.git

Top comments (1)

Collapse
 
sergeyleschev profile image
Sergey Leschev

I agree that handling variable data types in Codable is an important aspect of working with data in Swift. The ability to encode and decode different types of data seamlessly is a powerful tool for developers, especially when dealing with complex data structures.

Additionally, I would like to add that handling variable data types in Codable is not just a theoretical concept, but rather a practical necessity for many programming tasks. For example, when working with APIs or databases, we often encounter data that can have different types depending on the context. In such cases, Codable can prove to be invaluable for efficiently and accurately processing the data.

Overall, I believe that understanding and implementing variable data type handling in Codable is crucial for any Swift developer looking to build robust and reliable applications.