Site icon CodeWithSwift

Closures

Closures are self-contained blocks of functionality that can be passed around and used in your code. They can capture and store references to variables and constants from their surrounding context, making them extremely powerful for functional programming.

{ (parameters) -> ReturnType in
    // Code
}

//Example
let greet = { (name: String) -> String in
    return "Hello, \(name)!"
}

print(greet("Swift"))

//Output
Hello, Swift!

1.Closure as a Function Argument

func performOperation(_ operation: (Int, Int) -> Int) {
    let result = operation(4, 2)
    print("Result: \(result)")
}

// Passing a closure
performOperation { (a, b) -> Int in
    return a + b
}

// Output
Result: 6



2.Trailing Closure

If a closure is the last argument to a function, you can use trailing closure syntax.

performOperation { $0 * $1 }

//Output
Result: 8

3.Non-Escaping Closures

A non-escaping closure is executed within the scope of the function it is passed to. By default, function parameters that accept closures are non-escaping.

  1. The closure cannot outlive the function.
  2. It does not require explicit management of memory for captured variables.
  3. No need to use self explicitly when referring to instance properties or methods.

func performTask(closure: () -> Void) {
    print("Before closure execution")
    closure()
    print("After closure execution")
}

performTask {
    print("Closure is running")
}

//Output
Before closure execution
Closure is running
After closure execution

4.Escaping Closure

An escaping closure is executed after the function returns. It escapes the function’s scope, meaning it is stored for later execution, often in asynchronous tasks or completion handlers. To mark a closure as escaping, use the @escaping keyword.

  1. Outlives the function it is passed to.
  2. Captures variables in its context, potentially creating strong reference cycles.
  3. Requires explicit use of self when referring to instance properties or methods.

var completionHandlers: [() -> Void] = []

func addCompletionHandler(_ handler: @escaping () -> Void) {
    completionHandlers.append(handler)
}

addCompletionHandler {
    print("Escaping closure executed later!")
}


completionHandlers.forEach { $0() }


// Output
Escaping closure executed later!


Escaping closures are commonly used in:

  1. Asynchronous Tasks
    E.g., Network requests or delayed operations.
  2. Completion Handlers
    For actions that should occur after a process completes.
  3. Storage for Later Execution
    E.g., Keeping a closure in an array or variable for future use.

Capture List

A capture list in Swift is used within a closure to define how the closure should manage captured variables. It is primarily used to prevent strong reference cycles or to control the ownership of variables captured by the closure.

Capturing Variables by Reference

By default, closures capture variables by reference. This means the closure retains access to the latest value of the variable, even if it changes after the closure is created.

var fruit = "Apple"

let closure = {
    return fruit
}

print("\(closure())")  // Output: Apple

fruit = "Banana"

print("\(closure())")  // Output: Banana

1.Initially, the fruit variable has the value "Apple".

2.The closure captures the fruit variable by reference.

3.When we change the value of fruit to "Banana", the closure reflects this change because it holds a reference to the variable, not a copy.

Capture List for Immutable Copies

If you don’t want a closure to reflect changes in the captured variable, you can use a capture list. The capture list allows you to capture variables as immutable copies, effectively freezing their values at the time the closure is created.

var fruit = "Apple"

let closure = { [fruit] in
    return fruit
}

print("\(closure())")  // Output: Apple

fruit = "Banana"

print("\(closure())")  // Output: Apple

1.[fruit] in the capture list creates an immutable copy of fruit at the time the closure is created.

2.Even though we change the value of fruit to "Banana" later, the closure retains the original value ("Apple").

Exit mobile version