What is the purpose of the `CodingKeys` enum in custom Codable implementations? Provide an example.

iOS interview question for Intermediate practice.

Answer

The CodingKeys enum is used within a custom Codable implementation to map the keys used in the encoded format (e.g., JSON keys) to the property names used in your Swift type. Purpose: 1. Key Mapping: Its primary purpose is to bridge the gap when the names differ (e.g., snakecase in JSON vs. camelCase in Swift). 2. Selective Coding: By only including cases in CodingKeys for the properties you want to encode or decode, you can effectively omit other properties from the serialization process (though this also requires custom init(from:) / encode(to:) implementations). 3. Readability: Explicitly defines the keys expected in the encoded data. Requirements: It must be a nested enum named exactly CodingKeys. It must conform to the CodingKey protocol. It must also explicitly declare its raw value type as String (enum CodingKeys: String, CodingKey). Each case in the enum corresponds to a property you want to encode/decode. The name of the enum case must match the Swift property name. The raw string value assigned to the enum case must match the key name used in the encoded format (e.g., JSON). Example: Suppose you have JSON like this: json { "userid": 123, "username": "alice", "lastlogintimestamp": 1679900000 } And a Swift struct like this: swift struct User: Codable { let userID: Int let username: String let lastLogin: Date // Note: lastLogin type mismatch needs custom init/encode too, // but CodingKeys handles the naming difference. } To map the JSON keys to the Swift properties, you implement CodingKeys: swift struct User: Codable { let userID: Int let username: String let lastLogin: Date // Define the mapping between JSON keys and Swift properties enum CodingKeys: String, CodingKey { case userID = "userid" // Swift 'userID' maps to JSON 'userid' case username = "username" // Swift 'username' maps to JSON 'username' case lastLogin = "lastlogintimestamp" // Swift 'lastLogin' maps to JSON 'lastlogintimestamp' } // Custom init/encode would be needed here to handle Date <- Timestamp conversion // init(from decoder: Decoder) throws { ... } // func encode(to encoder: Encoder) throws { ... } } Now, when you use JSONDecoder or JSONEncoder with the User type, it will use the CodingKeys enum to correctly associate userid with userID, username with username, etc., during decoding and encoding.

Explanation

If you only need to map some keys and the rest match, you still need to include all properties you want to encode/decode as cases in your CodingKeys enum.

Related Questions