Swift Structs and Classes

Swift favors value types (structs) over reference types (classes). Closures are everywhere in Swift — they're used for callbacks, higher-order functions, and lazy evaluation.

Structs

SWIFT
// Structs are value types (copied, not shared)
struct Point {
    let x: Double
    let y: Double
    
    // Computed property
    var magnitude: Double {
        sqrt(x * x + y * y)
    }
    
    // Method
    func distance(to other: Point) -> Double {
        let dx = x - other.x
        let dy = y - other.y
        return sqrt(dx * dx + dy * dy)
    }
    
    // Mutating method (for value types)
    mutating func moveBy(dx: Double, dy: Double) {
        // self = Point(x: x + dx, y: y + dy)
    }
}

let p1 = Point(x: 3, y: 4)
print(p1.magnitude)  // 5.0
print(p1.distance(to: Point(x: 0, y: 0)))  // 5.0

// Struct with default values
struct User {
    var name: String
    var email: String
    var age: Int = 0
    var isActive: Bool = true
}

var alice = User(name: "Alice", email: "alice@test.com")
alice.age = 28  // Can modify properties of var struct

Classes

SWIFT
// Classes are reference types (shared)
class BankAccount {
    let owner: String
    private(set) var balance: Double
    
    init(owner: String, balance: Double = 0) {
        self.owner = owner
        self.balance = balance
    }
    
    func deposit(_ amount: Double) {
        balance += amount
    }
    
    func withdraw(_ amount: Double) -> Bool {
        guard balance >= amount else { return false }
        balance -= amount
        return true
    }
}

let account = BankAccount(owner: "Alice", balance: 1000)
account.deposit(500)
account.withdraw(200)  // true

Struct vs Class

Aspect Struct Class
Type Value (copied) Reference (shared)
Identity No Yes (===)
Inheritance No Yes
Mutating mutating keyword Automatic
Deinitializer No deinit
Default Prefer this When needed

Use struct for: data models, views, value types Use class for: shared state, delegates, inheritance, Objective-C interop

Closures

SWIFT
// Basic closure
let greet = { (name: String) -> String in
    return "Hello, \(name)!"
}
greet("Alice")

// Trailing closure syntax
func perform(action: () -> Void) {
    action()
}

perform { print("Done!") }

// Closure with parameters
numbers.map { $0 * 2 }             // $0 is first parameter
numbers.filter { $0 > 5 }
numbers.reduce(0, +)

// Sorting with closures
let names = ["Charlie", "Alice", "Bob"]
let sorted = names.sorted { $0 < $1 }  // ["Alice", "Bob", "Charlie"]

// Closure capture
func makeCounter() -> () -> Int {
    var count = 0
    return {
        count += 1  // Captures count
        return count
    }
}

let counter = makeCounter()
counter()  // 1
counter()  // 2
counter()  // 3

Common Closures in Swift

SWIFT
// Sorting
let sorted = names.sorted(by: { (a, b) -> Bool in
    return a < b
})

// Shorthand
let sorted2 = names.sorted { $0 < $1 }

// Filtering
let longNames = names.filter { $0.count > 3 }

// Mapping
let uppercased = names.map { $0.uppercased() }

// Reducing
let totalLength = names.reduce(0) { $0 + $1.count }

// Chaining
let result = names
    .filter { $0.count > 3 }
    .map { $0.uppercased() }
    .sorted()

// completion handler pattern
func fetchData(from url: String, completion: @escaping (Result<Data, Error>) -> Void) {
    // Async operation...
    URLSession.shared.dataTask(with: URL(string: url)!) { data, response, error in
        if let error = error {
            completion(.failure(error))
        } else if let data = data {
            completion(.success(data))
        }
    }.resume()
}

// Usage
fetchData(from: "https://api.example.com") { result in
    switch result {
    case .success(let data):
        print("Got \(data.count) bytes")
    case .failure(let error):
        print("Error: \(error)")
    }
}

💡 Tip: Default to structs. Only use classes when you need reference semantics (shared state), inheritance, or Objective-C compatibility.

Next: Swift Protocols and Error Handling