What is a closure in Swift?

A closure is a block of code you can pass and store like a value, and it can capture constants and variables from the surrounding scope

Answer

The core idea

A closure is a self-contained block of code that you can pass around and store like a value. Named functions are also closures under the hood, but interview talk usually means the brace syntax { ... } and the way that block can capture constants and variables from the surrounding scope.

The short interview answer is: a closure is passable code that can remember and use values from the place where it was created.

1. Store a closure in a variable

A closure can live in a let or var and be called later, just like a function:

swift 5.2
let greet = { (name: String) -> String in
    "Hello, \(name)!"
}

print(greet("Alex")) // Hello, Alex!

2. Pass a closure into a function

Functions often take closures as parameters so callers supply custom behavior:

swift 5.2
func perform(_ action: () -> Void) {
    print("before")
    action()
    print("after")
}

perform {
    print("doing work")
}

Trailing-closure syntax is the same idea with less punctuation when the closure is the last argument.

3. Use closures with collections

Swift's collection APIs are built around closures. You pass the rule, the collection does the looping:

swift 5.2
let names = ["Zara", "Alex", "Sam"]

let sorted = names.sorted { $0 < $1 }
let shortNames = names.filter { $0.count <= 3 }
let labels = names.map { "Hello, \($0)!" }

print(sorted)      // ["Alex", "Sam", "Zara"]
print(shortNames)  // ["Sam"]
print(labels)      // ["Hello, Zara!", "Hello, Alex!", "Hello, Sam!"]

$0 and $1 are shorthand argument names. For a one-expression closure, Swift can also infer the return value.

4. Capture values from the enclosing scope

Capture is what makes a closure more than an anonymous function. Here makeCounter returns a closure that keeps using the same count after makeCounter has returned:

swift 5.2
func makeCounter() -> () -> Int {
    var count = 0
    return {
        count += 1 // ✅ Captures `count` from the enclosing scope
        return count
    }
}

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

The returned closure still owns that captured state, so each call advances the same counter.

5. Use a completion-handler style callback

A common real-world shape is “do work, then run this closure with the result”:

swift 5.2
func loadMessage(completion: (String) -> Void) {
    let message = "Loaded"
    completion(message)
}

loadMessage { message in
    print(message) // Loaded
}

Network APIs historically used @escaping completions of this form. Escaping means the closure may be stored and called after the function returns, which is also why capture of self matters in class code.

6. Why it matters

Closures show up wherever Swift wants injectable behavior: sorting, mapping, animations, button actions, and async callbacks. Because a closure can capture surrounding state, it can keep values and objects alive across calls. Strong capture of self inside a stored escaping closure is a common retain-cycle source, which is a separate interview topic.

Interview angle

Lead with the definition: passable code that can capture enclosing values. Then walk a few uses in order: store one, pass one, use one with map/filter/sorted, show capture with a counter, and mention completion handlers. Close by noting that escaping capture is why [weak self] comes up later, and point at the Swift book chapter on Closures.