struct User: Codable { let name: String; let age: Int } gains full JSON encoding and decoding automatically — the compiler synthesizes the implementation with zero manual code, as long as every property's name matches the corresponding JSON key exactly. JSONDecoder().decode(User.self, from: data) and JSONEncoder().encode(user) perform the actual conversion. When a JSON key genuinely doesn't match the Swift property name — typically snake_case JSON against camelCase Swift — a custom CodingKeys enum, conforming to CodingKey, remaps each property to its actual JSON key explicitly.
Automatic Codable conformance
User writes NO encode or decode logic at all — conforming to Codable, with property names matching the JSON exactly, is genuinely sufficient for the compiler to synthesize the whole implementation.
struct User: Codable {
let name: String
let age: Int
}
let jsonString = "{\"name\": \"Alice\", \"age\": 30}"
let json = jsonString.data(using: .utf8)!
let user = try JSONDecoder().decode(User.self, from: json)
print(user.name) // Alice -- plain print() of a String never adds quotes
let encoded = try JSONEncoder().encode(user)
print(String(data: encoded, encoding: .utf8)!) // something like {"name":"Alice","age":30} -- JSONEncoder does NOT guarantee key order by default; use .sortedKeys on outputFormatting if the order needs to be deterministicCodingKeys: remapping mismatched key names
CodingKeys tells the compiler exactly which JSON key each property corresponds to — fullName maps to the JSON's actual full_name key, without needing any manual encode/decode code beyond this one enum.
struct User: Codable {
let fullName: String
let age: Int
enum CodingKeys: String, CodingKey {
case fullName = "full_name" // maps Swift's fullName to JSON's full_name
case age
}
}
let jsonString = "{\"full_name\": \"Alice Smith\", \"age\": 30}"
let json = jsonString.data(using: .utf8)!
let user = try JSONDecoder().decode(User.self, from: json)
print(user.fullName) // "Alice Smith"Nested and array structures
Codable handles nested types and arrays of Codable elements automatically too — as long as every nested type also conforms, the whole structure decodes in one call with no extra code.
struct Address: Codable {
let city: String
}
struct User: Codable {
let name: String
let addresses: [Address] // nested + array — both handled automatically
}