Chapters

Hide chapters

Swift Cookbook

Live Edition · Multiplatform · Swift · Editor agnostic

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.

© 2024 Kodeco Inc.