Handle Custom Keys & Missing Values while Decoding in Swift
Written by Team Kodeco
Handling custom keys and missing values during decoding in Swift involves using CodingKeys and the decodeIfPresent method, respectively.
The CodingKeys enumeration is used to map between the property names in the Swift code and the keys in the JSON data. For example, if the key in the JSON data is different from the property name in the Swift code, the property name can be mapped to the correct JSON key using the CodingKeys enumeration.
For example, consider the following JSON data:
{
"make_name": "Toyota",
"model_name": "Camry",
"year_made": 2019,
"color": "Black"
}
Here, the keys in the JSON data are different from the property names in the Swift code. To map these keys, the following CodingKeys enumeration can be used:
import Foundation
struct Car: Codable {
let make: String
let model: String
let year: Int
let color: String
private enum CodingKeys: String, CodingKey {
case make = "make_name"
case model = "model_name"
case year = "year_made"
case color
}
}
You can now decode the JSON as follows:
let jsonData = """
[
{
"make_name": "Toyota",
"model_name": "Camry",
"year_made": 2019,
"color": "Black"
}
]
""".data(using: .utf8)!
let decoder = JSONDecoder()
let cars = try decoder.decode([Car].self, from: jsonData)
print(cars)
// Output: [Car(make: "Toyota", model: "Camry", year: 2019, color: Optional("Black")]
Handling Missing Values During Decoding
Regarding handling missing values during decoding, Swift provides the decodeIfPresent
method that allows to decode an optional value and return nil if the value is not present in the JSON data. For example:
struct Car: Codable {
let make: String
let model: String
let year: Int
let color: String?
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
make = try container.decode(String.self, forKey: .make)
model = try container.decode(String.self, forKey: .model)
year = try container.decode(Int.self, forKey: .year)
color = try container.decodeIfPresent(String.self, forKey: .color)
}
}
In the above example, the color
property is declared as an optional and its value is decoded using decodeIfPresent()
. If the color
is not present in the JSON data, the value of color will be nil.
Let’s see what happens if you try to decode some JSON that does not contain the color
property:
let jsonData = """
[
{
"make": "Toyota",
"model": "Camry",
"year": 2019,
}
]
""".data(using: .utf8)!
let decoder = JSONDecoder()
let cars = try decoder.decode([Car].self, from: jsonData)
print(cars)
// Output: [Car(make: "Toyota", model: "Camry", year: 2019, color: nil]
The JSON successfully decodes, but color
is set to nil
, as expected.