What are closures in Swift? What is a capture list in closures? What are escaping and non-escaping closures?
Closures in Swift are self-contained blocks of function code that can be passed and used within code. Closures can capture and store references to any constants and variables from their surrounding context.
Basic Concepts of Closures:
- Closures are reference types
- Can be passed as parameters to functions
- Can be returned as function results
- Can be stored in variables or constants
- Three forms: global functions, nested functions, closure expressions
Closure Syntax:
swift// Complete form let greeting = { (name: String) -> String in return "Hello, \(name)" } // Simplified form let greeting = { name in "Hello, \(name)" } // Shortest form (using parameter shorthand) let greeting: (String) -> String = { "Hello, \($0)" }
Capture List:
- Used to explicitly declare variables the closure will capture
- Use
[weak self]or[unowned self]to avoid retain cycles - Use
[weak var = weakVar]to capture weak references - Use
[unowned var = var]to capture unowned references - Example:
swift
let closure = { [weak self] in self?.doSomething() }
Escaping Closures:
- Closures that are called after the function returns
- Marked with
@escaping - Must explicitly reference
self - Commonly used for async operations, callbacks, network requests
- Example:
swift
func request(completion: @escaping (Result) -> Void) { DispatchQueue.global().async { let result = fetchData() completion(result) } }
Non-Escaping Closures:
- Closures that are called before the function returns
- Default to non-escaping in Swift 3.0+
- Can implicitly reference
self - Better performance, compiler can optimize
- Example:
swift
func process(_ closure: (Int) -> Void) { closure(42) }
Best Practices:
- Use capture lists to avoid retain cycles
- Prioritize non-escaping closures
- Reasonably use trailing closure syntax
- Use
weakorunownedfor self references - Consider the memory overhead of closures