Codable and JSON
struct Post: Codable, Identifiable {
let id: Int
let userId: Int
var title: String
var body: String
var tags: [String]? // optional: missing keys are fine
let publishedAt: Date
enum CodingKeys: String, CodingKey { // rename keys
case id, userId = "user_id", title, body, tags
case publishedAt = "published_at"
}
}
let json = """
{ "id": 1, "user_id": 7, "title": "Hello", "body": "World", "published_at": "2025-10-24T10:00:00Z" }
""".data(using: .utf8)!
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
// decoder.keyDecodingStrategy = .convertFromSnakeCase // alternative to CodingKeys
let post = try decoder.decode(Post.self, from: json)
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
encoder.dateEncodingStrategy = .iso8601
let data = try encoder.encode(post)
print(String(decoding: data, as: UTF8.self))39.1 Custom Encoding/Decoding
Nested containers, singleValueContainer, unkeyedContainer, PropertyListEncoder/Decoder, error handling with DecodingError (.keyNotFound, .typeMismatch, .dataCorrupted), and dynamic JSON (JSONSerialization, or a custom JSONValue enum).
struct Temperature: Codable {
let celsius: Double
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let c = try container.decodeIfPresent(Double.self, forKey: .celsius) {
celsius = c
} else {
let f = try container.decode(Double.self, forKey: .fahrenheit)
celsius = (f - 32) * 5 / 9
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(celsius, forKey: .celsius)
}
enum CodingKeys: String, CodingKey { case celsius, fahrenheit }
}
enum Shape: Codable { // enums with associated values are Codable (Swift 5.5+)
case circle(radius: Double)
case square(side: Double)
}