Lesson 58Structs

Codable & Hashable

Built-in Protocols

Swift provides powerful protocols that add common functionality to your structs with minimal code. Just conform and Swift does the work!

Essential Protocols

Equatable

Compare with == and !=

struct X: Equatable

Hashable

Use in Set and Dictionary

struct X: Hashable

Comparable

Compare with <, >, etc.

struct X: Comparable

Codable

JSON encode/decode

struct X: Codable

Codable Deep Dive

// Codable = Encodable + Decodable
struct User: Codable {
    var name: String
    var age: Int
}

CodingKeys

Use CodingKeys to map JSON keys to different property names:

case authorName = "author_name"
main.swift
// CODABLE & HASHABLE
// Built-in protocols for common functionality

// ===== EQUATABLE =====
// Compare structs with ==
struct Point: Equatable {
    var x: Int
    var y: Int
}

let p1 = Point(x: 10, y: 20)
let p2 = Point(x: 10, y: 20)
let p3 = Point(x: 5, y: 5)

print(p1 == p2)  // true
print(p1 == p3)  // false

// ===== HASHABLE =====
// Use structs in Sets and as Dictionary keys
struct User: Hashable {
    var id: Int
    var name: String
}

let user1 = User(id: 1, name: "Alice")
let user2 = User(id: 2, name: "Bob")

var userSet: Set<User> = [user1, user2]
var userScores: [User: Int] = [user1: 100, user2: 85]

print(userScores[user1]!)  // 100

// ===== COMPARABLE =====
// Enable <, >, <=, >= comparisons
struct Score: Comparable {
    var points: Int
    var name: String

    static func < (lhs: Score, rhs: Score) -> Bool {
        return lhs.points < rhs.points
    }
}

let scores = [
    Score(points: 85, name: "Alice"),
    Score(points: 92, name: "Bob"),
    Score(points: 78, name: "Charlie")
]

let sorted = scores.sorted()  // Sorted by points
print(sorted.map { $0.name })  // ["Charlie", "Alice", "Bob"]

// ===== CODABLE =====
// Encode/decode to JSON, PropertyList, etc.
struct Product: Codable {
    var id: Int
    var name: String
    var price: Double
    var inStock: Bool
}

let product = Product(id: 1, name: "iPhone", price: 999.99, inStock: true)

// ENCODE TO JSON
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

if let jsonData = try? encoder.encode(product),
   let jsonString = String(data: jsonData, encoding: .utf8) {
    print(jsonString)
    // {
    //   "id" : 1,
    //   "name" : "iPhone",
    //   "price" : 999.99,
    //   "inStock" : true
    // }
}

// DECODE FROM JSON
let jsonString = """
{
    "id": 2,
    "name": "MacBook",
    "price": 1299.99,
    "inStock": false
}
"""

let decoder = JSONDecoder()
if let data = jsonString.data(using: .utf8),
   let decoded = try? decoder.decode(Product.self, from: data) {
    print(decoded.name)  // MacBook
}

// CUSTOM CODING KEYS
struct Article: Codable {
    var title: String
    var body: String
    var authorName: String

    enum CodingKeys: String, CodingKey {
        case title
        case body = "content"
        case authorName = "author_name"
    }
}

// NESTED CODABLE
struct Order: Codable {
    var orderId: Int
    var customer: Customer
    var items: [OrderItem]
}

struct Customer: Codable {
    var name: String
    var email: String
}

struct OrderItem: Codable {
    var productId: Int
    var quantity: Int
}

Try It Yourself!

Create a Book struct that's Codable with custom CodingKeys. Encode it to JSON and decode it back!