Lesson 60Structs

Structs Practice

Module Complete!

Time to practice everything you've learned about structs. Complete these exercises to solidify your understanding!

Exercises Overview

1. Basic Struct

Book with properties & methods

2. Protocol Conformance

Shapes with Shape protocol

3. Codable JSON

Parse API responses

4. Shopping Cart

Complex struct system

5. Value Types

Copy-on-assignment demo

What You've Learned

  • Struct basics and properties
  • Methods and mutating keyword
  • Initializers (memberwise, custom, failable)
  • Value types vs reference types
  • Extensions for organizing code
  • Protocols (Equatable, Hashable, Codable)
  • Best practices for clean code

Next Up: Classes!

In the next module, you'll learn about Classes - Swift's reference types with inheritance, deinitializers, and shared state!

practice.swift
// STRUCTS PRACTICE - PUTTING IT ALL TOGETHER!

// ===== EXERCISE 1: Basic Struct =====
// Create a Book struct with properties and methods

struct Book: Equatable, Hashable {
    var title: String
    var author: String
    var pages: Int
    var currentPage: Int = 0

    var progress: Double {
        return Double(currentPage) / Double(pages) * 100
    }

    var isFinished: Bool {
        return currentPage >= pages
    }

    mutating func read(pages count: Int) {
        currentPage = min(currentPage + count, pages)
    }
}

var myBook = Book(title: "Swift Guide", author: "Apple", pages: 300)
myBook.read(pages: 50)
print("Progress: \(myBook.progress)%")  // 16.67%

// ===== EXERCISE 2: Protocol Conformance =====
// Create shapes that conform to a protocol

protocol Shape {
    var area: Double { get }
    var perimeter: Double { get }
    func describe() -> String
}

struct Circle: Shape {
    var radius: Double

    var area: Double {
        return Double.pi * radius * radius
    }

    var perimeter: Double {
        return 2 * Double.pi * radius
    }

    func describe() -> String {
        return "Circle with radius \(radius)"
    }
}

struct Square: Shape {
    var side: Double

    var area: Double { return side * side }
    var perimeter: Double { return 4 * side }

    func describe() -> String {
        return "Square with side \(side)"
    }
}

let shapes: [Shape] = [Circle(radius: 5), Square(side: 4)]
for shape in shapes {
    print("\(shape.describe()): Area = \(shape.area)")
}

// ===== EXERCISE 3: Codable JSON Parsing =====
// Parse API response into structs

struct APIResponse: Codable {
    var users: [APIUser]
    var total: Int
}

struct APIUser: Codable {
    var id: Int
    var name: String
    var email: String
    var isActive: Bool

    enum CodingKeys: String, CodingKey {
        case id, name, email
        case isActive = "is_active"
    }
}

let json = """
{
    "users": [
        {"id": 1, "name": "Alice", "email": "[email protected]", "is_active": true},
        {"id": 2, "name": "Bob", "email": "[email protected]", "is_active": false}
    ],
    "total": 2
}
"""

if let data = json.data(using: .utf8),
   let response = try? JSONDecoder().decode(APIResponse.self, from: data) {
    for user in response.users {
        print("\(user.name): \(user.isActive ? "Active" : "Inactive")")
    }
}

// ===== EXERCISE 4: Complex Struct with Extensions =====
// Build a shopping cart system

struct Product: Identifiable, Hashable {
    let id: UUID
    var name: String
    var price: Double

    init(name: String, price: Double) {
        self.id = UUID()
        self.name = name
        self.price = price
    }
}

struct CartItem {
    var product: Product
    var quantity: Int

    var subtotal: Double {
        return product.price * Double(quantity)
    }
}

struct ShoppingCart {
    private(set) var items: [CartItem] = []

    var totalItems: Int {
        return items.reduce(0) { $0 + $1.quantity }
    }

    var totalPrice: Double {
        return items.reduce(0) { $0 + $1.subtotal }
    }

    mutating func add(_ product: Product, quantity: Int = 1) {
        if let index = items.firstIndex(where: { $0.product.id == product.id }) {
            items[index].quantity += quantity
        } else {
            items.append(CartItem(product: product, quantity: quantity))
        }
    }

    mutating func remove(_ product: Product) {
        items.removeAll { $0.product.id == product.id }
    }

    mutating func clear() {
        items.removeAll()
    }
}

extension ShoppingCart: CustomStringConvertible {
    var description: String {
        var result = "Shopping Cart (\(totalItems) items):\n"
        for item in items {
            result += "  - \(item.product.name) x\(item.quantity) = $\(item.subtotal)\n"
        }
        result += "Total: $\(totalPrice)"
        return result
    }
}

var cart = ShoppingCart()
let iPhone = Product(name: "iPhone", price: 999)
let airPods = Product(name: "AirPods", price: 199)

cart.add(iPhone)
cart.add(airPods, quantity: 2)
print(cart)

// ===== EXERCISE 5: Value Type Behavior =====
// Demonstrate copy-on-assignment

struct GameState {
    var level: Int
    var score: Int
    var lives: Int

    mutating func nextLevel() {
        level += 1
        score += 100
    }

    mutating func loseLife() {
        lives -= 1
    }
}

var currentGame = GameState(level: 1, score: 0, lives: 3)
var savedGame = currentGame  // Creates a copy!

currentGame.nextLevel()
currentGame.loseLife()

print("Current: Level \(currentGame.level), Lives \(currentGame.lives)")
print("Saved: Level \(savedGame.level), Lives \(savedGame.lives)")
// Current: Level 2, Lives 2
// Saved: Level 1, Lives 3 (unchanged!)

print("\nšŸŽ‰ Congratulations! You've completed the Structs module!")

Final Challenge!

Create a TodoList app with Todo struct (id, title, isCompleted, priority) and a TodoManager struct with add, remove, toggle, and filter methods!