Working with closures in Swift

April 19, 2022

In today’s article, we’ll be looking at the concept of Closures in Swift, and, oh boy, the concept of closure was once a nightmare for me! Closures are a powerful and essential feature in Swift programming language that allow developers to define a block of code that can be executed at a later time. Let’s deep dive in learning more about closures.

What are Closures?

A closure is a self-contained block of code that can be passed around and used in your code. Simplifying, closures can capture and store references to any constants and variables from the context in which they are defined. This is called capturing, and it allows closures to maintain state between multiple invocations. In Swift, closures are treated as first-class citizens, meaning they can be assigned to variables and passed as arguments to functions just like any other data type.

Syntax of Closures:

Closures are defined using the following syntax:

{ (parameters) -> return type in
    // code to be executed
}

The parameters and return type are optional and can be omitted if the closure does not take any arguments or return a value. The in keyword separates the closure header from the closure body.

Here is an example of a closure that takes two integers as arguments and returns their sum:

let sumClosure = { (a: Int, b: Int) -> Int in
    return a + b
}

Using Closures in your projects:

Closures can be used in a variety of ways in Swift. One of the most common uses of closures is in functions that take other functions as arguments. For example, the sorted(by:) method on arrays takes a closure that compares two elements and returns a boolean value indicating whether the first element should come before the second element in the sorted array.

let numbers = [5, 2, 7, 1, 9]
let sortedNumbers = numbers.sorted(by: { (a, b) -> Bool in
    return a < b
})

In this example, the closure passed to sorted(by:) takes two integers and returns a boolean value indicating whether the first integer is less than the second integer. The sorted array is returned as the result of the sorted(by:) method.

Capturing Values with Closures:

Closures can capture and store references to any constants and variables from the context in which they are defined. This is called capturing, and it allows closures to maintain state between multiple invocations.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen() // returns 10
incrementByTen() // returns 20
incrementByTen() // returns 30

In this example, the makeIncrementer(forIncrement:) function returns a closure that captures a reference to the runningTotal variable. Each time the closure is called, it increments the running total by the amount passed to makeIncrementer(forIncrement:).

Conclusion

Closures are a powerful and essential feature in Swift programming language that allow developers to define a block of code that can be executed at a later time. Closures can capture and store references to any constants and variables from the context in which they are defined. This is called capturing, and it allows closures to maintain state between multiple invocations. In Swift, closures are treated as first-class citizens, meaning they can be assigned to variables and passed as arguments to functions just like any other data type.

This was all about Closures in Swift.

Thank you for reading this far.