What is Codable?

Codable is a protocol that enables you to encode and decode data in various formats, such as JSON, XML, or plist. In this blog post, I will explain what Codable is, how to use it, and some common use cases.

Codable is a type alias for two protocols: Encodable and Decodable. Encodable enables you to convert a type into a data representation, such as JSON. Decodable enables you to convert a data representation into a type, such as JSON. Codable combines both protocols, so you can encode and decode a type with a single declaration.

Swift Docs-Codable

For example, let’s say you have a struct that represents a person:

struct Person {
    var name: String
    var age: Int
    var hobbies: [String]
}

To make this struct conform to Codable, you simply have to add the protocol to its declaration:

struct Person: Codable {
    var name: String
    var age: Int
    var hobbies: [String]
}

That’s it! Now you can encode and decode instances of Person using various encoders and decoders, such as JSONEncoder and JSONDecoder.

How to use Codable for JSON data type?

To encode a type that conforms to Codable, you need to use an encoder that matches the format you want to encode to. For example, to encode a Person instance into JSON data, you can use JSONEncoder:

// Create a Person instance
let person = Person(name: "Alice", age: 25, hobbies: ["Reading", "Coding", "Gaming"])

// Create a JSON encoder
let encoder = JSONEncoder()

// Try to encode the person into JSON data
do {
    let data = try encoder.encode(person)
    print(data) // Prints the JSON data
} catch {
    print(error) // Prints any encoding error
}

To decode a type that conforms to Codable, you need to use a decoder that matches the format you want to decode from. For example, to decode a Person instance from JSON data, you can use JSONDecoder:

// Create some JSON data
let data = """
{
    "name": "Bob",
    "age": 30,
    "hobbies": ["Cooking", "Traveling", "Blogging"]
}
""".data(using: .utf8)!

// Create a JSON decoder
let decoder = JSONDecoder()

// Try to decode the person from JSON data
do {
    let person = try decoder.decode(Person.self, from: data)
    print(person) // Prints the Person instance
} catch {
    print(error) // Prints any decoding error
}

Note that the encoder and decoder will use the same property names as the type by default. If you want to use different keys for encoding and decoding, you can define a CodingKeys enum that conforms to CodingKey inside your type:

struct Person: Codable {
    var name: String
    var age: Int
    var hobbies: [String]

    // Define custom keys for encoding and decoding
    enum CodingKeys: String, CodingKey {
        case name = "fullName"
        case age = "years"
        case hobbies = "interests"
    }
}

Now the encoder and decoder will use the raw values of the CodingKeys enum instead of the property names.

Here is a possible addition to the blog post on Codable with plist examples:


How to use Codable for plist data type?

plist (short for property list) is a format that stores data in a structured and human-readable way. It can be used to store various types of data, such as strings, numbers, booleans, arrays, dictionaries, dates, or data. plist files have the extension .plist and can be edited with Xcode or any text editor.

To encode and decode data in plist format, you can use PropertyListEncoder and PropertyListDecoder. They work in the same way as JSONEncoder and JSONDecoder, except they use plist instead of JSON. For example, you can encode a Person instance into plist data using PropertyListEncoder:

// Create a Person instance
let person = Person(name: "Alice", age: 25, hobbies: ["Reading", "Coding", "Gaming"])

// Create a plist encoder
let encoder = PropertyListEncoder()

// Try to encode the person into plist data
do {
    let data = try encoder.encode(person)
    print(data) // Prints the plist data
} catch {
    print(error) // Prints any encoding error
}

You can also decode a Person instance from plist data using PropertyListDecoder:

// Create some plist data
let data = """
<dict>
    <key>name</key>
    <string>Bob</string>
    <key>age</key>
    <integer>30</integer>
    <key>hobbies</key>
    <array>
        <string>Cooking</string>
        <string>Traveling</string>
        <string>Blogging</string>
    </array>
</dict>
""".data(using: .utf8)!

// Create a plist decoder
let decoder = PropertyListDecoder()

// Try to decode the person from plist data
do {
    let person = try decoder.decode(Person.self, from: data)
    print(person) // Prints the Person instance
} catch {
    print(error) // Prints any decoding error
}

Note that the encoder and decoder will use the same property names as the type by default. If you want to use different keys for encoding and decoding, you can define a CodingKeys enum that conforms to CodingKey inside your type, as shown in the previous section.

You can use Codable with plist to store and retrieve data from various sources, such as files or user defaults. For example, you can write and read plist data from a file using FileManager:

// Get the URL of the Documents directory
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

// Create a file URL for the plist file
let fileURL = documentsURL.appendingPathComponent("person.plist")

// Create a Person instance
let person = Person(name: "Alice", age: 25, hobbies: ["Reading", "Coding", "Gaming"])

// Create a plist encoder
let encoder = PropertyListEncoder()

// Try to encode the person into plist data and write it to the file
do {
    let data = try encoder.encode(person)
    try data.write(to: fileURL)
} catch {
    print(error) // Prints any encoding or writing error
}

// Create a plist decoder
let decoder = PropertyListDecoder()

// Try to read the plist data from the file and decode it into a Person instance
do {
    let data = try Data(contentsOf: fileURL)
    let person = try decoder.decode(Person.self, from: data)
    print(person) // Prints the Person instance
} catch {
    print(error) // Prints any reading or decoding error
}

What are some common use cases for Codable?

Codable is very useful for working with data from various sources, such as APIs, databases, files, or user defaults. Here are some examples of situations where you can use Codable in your projects:

  • Fetching data from an API: You can use URLSession or Alamofire to make network requests and get data in JSON format. You can then use JSONDecoder to decode the data into your custom types that conform to Codable.
  • Saving data to a database: You can use Core Data or Realm to store and manage your data in a database. You can then use NSKeyedArchiver or PropertyListEncoder to encode your custom types that conform to Codable into data that can be stored in the database.
  • Writing data to a file: You can use FileManager or Data to write and read data from files in your app’s directory. You can then use JSONEncoder or PropertyListEncoder to encode your custom types that conform to Codable into data that can be written to a file.
  • Storing data in user defaults: You can use UserDefaults to store and retrieve small amounts of user preferences or settings. You can then use JSONEncoder or PropertyListEncoder to encode your custom types that conform to Codable into data that can be stored in user defaults.

Conclusion

Codable is a protocol that enables you to encode and decode data in various formats, such as JSON, XML, or plist. You can make any type conform to Codable by adding the protocol to its declaration, and use various encoders and decoders to convert between data and types. Codable can help you work with data from various sources, such as APIs, databases, files, or user defaults.

Thanks for reading!