iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Closures

A closure is a function literal. Swift has the cleanest closure syntax in the C-family: type-inference, trailing-closure syntax, shorthand argument names ($0, $1), implicit returns.

Closures — the four shapes

EXAMPLE
// 1) Full form
let adder: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
    return a + b
}

// 2) Inferred parameter types
let adder2: (Int, Int) -> Int = { a, b in a + b }

// 3) Shorthand argument names
let adder3: (Int, Int) -> Int = { $0 + $1 }

// 4) Trailing closure — the syntactic unlock
let nums = [1, 2, 3, 4, 5]
let doubled = nums.map { $0 * 2 }
let evens   = nums.filter { $0.isMultiple(of: 2) }
let total   = nums.reduce(0, +)

// 5) Multiple trailing closures (Swift 5.3+)
UIView.animate(withDuration: 0.3) {
    self.label.alpha = 0
} completion: { _ in
    self.label.removeFromSuperview()
}

// 6) Capture lists — control what closure captures
class Vote {
    var count = 0
    func register(_ block: @escaping () -> Void) {}
    func setup() {
        register { [weak self] in        // weak — avoid retain cycle
            self?.count += 1
        }
        register { [unowned self] in     // unowned — guarantees nil-safe
            self.count += 1
        }
    }
}

// 7) @escaping — closure outlives the function call
func fetch(_ url: URL, then: @escaping (Data) -> Void) {
    URLSession.shared.dataTask(with: url) { data, _, _ in
        guard let data else { return }
        then(data)
    }.resume()
}

// 8) @autoclosure — defer evaluation
func require(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String) {
    if !condition() {
        fatalError(message())
    }
}
require(user != nil, "user must be signed in")   // message only built on failure

// 9) Async closures
func handle(_ work: @escaping () async throws -> Int) {
    Task {
        let n = try await work()
        print(n)
    }
}
handle { try await fetchUserCount() }

// 10) Higher-order closures with proper type inference
let users = ["Ada", "Bo", "Cy"]
users.sorted { $0.count < $1.count }

Why it matters

Trailing-closure syntax + shorthand argument names make Swift APIs read like English. Lean on them, and the imperative loop with explicit names almost disappears from your code.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
let nums = [1, 2, 3, 4]
let doubled = nums.map { $0 * 2 }
let evens = nums.filter { $0 % 2 == 0 }
let total = nums.reduce(0, +)
Try it Yourself »

Discussion

Loading…