What is a closure?
sobes.tech AI
Answer from AI
A closure in Swift is a self-contained block of functionality ({}) that can be passed around and used in your code. Closures can capture and store references to constants and variables from the context in which they are defined.
Examples of usage:
- As arguments to functions (e.g., Completion Handlers).
- To define behavior when enumerating collections (e.g., using
map,filter,reduce,sortedmethods). - For deferred execution of code.
Syntax:
// Basic syntax
{ (parameters) -> returnType in
statements
}
// Example of a closure accepting an Int and returning a String
let integerToString: (Int) -> String = { (number: Int) -> String in
return "Number: \(number)"
}
Features:
- Automatic capturing of variables.
- Ability to define closures without explicitly specifying parameter types and return type (syntactic sugar).
- Use of shorthand argument names ($0, $1, etc.).
- Trailing closure syntax.
Variable capturing:
A closure can capture variables from its surrounding environment. By default, capturing occurs by reference. Even if the original variable goes out of scope, the closure still maintains access to it.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0 // External variable
let incrementer: () -> Int = { // Closure
runningTotal += amount // Captures runningTotal and amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Output: 10
print(incrementByTen()) // Output: 20
Capture Lists:
Used to explicitly specify how variables should be captured — by value or by reference — and to avoid strong reference cycles (retain cycles).
class MyClass {
var value = 0
lazy var myClosure: () -> Void = { [self, value] in // Capture self by reference, value by value
print("Value of self.value: \(self.value)")
print("Captured value: \(value)")
}
deinit {
print("MyClass instance deallocated")
}
}
To prevent strong reference cycles when capturing class objects, use [weak self] or [unowned self] syntax.
class ViewController {
var dataFetcher: DataFetcher?
func fetchData() {
dataFetcher?.fetch { [weak self] result in // Weak capture of self
guard let self = self else { return } // Check for self existence
// Handle result
}
}
}
class DataFetcher {
var completionHandler: ((Result<String, Error>) -> Void)?
func fetch(completion: @escaping (Result<String, Error>) -> Void) {
self.completionHandler = completion
// Asynchronous operation...
}
}