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:
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:
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:
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:
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()) // 2The 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”:
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.