A closure in Swift is a self-contained block of functionality that can be passed around and used throughout the code. Closures have a syntax that resembles a function without a name, written with curly braces and parameters followed by a return type and the in keyword. Closures can capture and store references to variables from their surrounding context, which gives them powerful flexibility and is the foundation for many functional programming patterns in Swift.
Trailing closure syntax is a convenience that lets developers write a closure argument after a function call's parentheses when the closure is the last argument. This makes code more readable, especially for functions like sorted, where numbers.sorted { $0 < $1 } is more natural than numbers.sorted(by: { $0 < $1 }). Closures passed in this way can also use shorthand argument names like $0, $1, and so on, when the parameter types can be inferred.
Closures have an important distinction between escaping and non-escaping behavior. By default, closure parameters are non-escaping, meaning they cannot be stored or called after the function returns. When a closure needs to be stored in a property or called asynchronously, the @escaping attribute marks it as eligible to outlive the function call. Closures that capture references to class instances can create retain cycles, in which two objects hold strong references to each other and prevent deallocation. Capture lists resolve this issue by declaring how values are captured: [weak self] captures a reference as a weak optional that becomes nil when the referenced object is deallocated, while [unowned] captures without increasing the reference count but assumes the value always exists.