What is closure in Swift?

Closures are self-contained functions that can be used in different places in the code. We can also assign closures to variables. They're similar to lambda functions in other coding languages. Closures can be in a few different forms.

Different forms of closures

  1. Global functions: They may be named or unnamed but do not capture any values.

  2. Nested functions: They may be named or unnamed but capture values from their enclosing functions.

  3. Closure expressions: They are unnamed and capture values from their surrounding context.

Closure expressions

Closure expressions are the most widely used form of closure. They are unnamed functions that capture values from their surrounding context. We use closure expression to write in-line functions in a brief syntax. A closure expression may or may not return a value.

Syntax

Closures have the following general syntax:

{ (parameters) -> returnType in
// closure body
}

We declare the arguments of the function in (parameters). Then we specify the return type, such as Int or String. After that, we insert the keyword in, followed by the body of the function.

Code example

A simple example of this is a closure that takes a number as an argument and returns the next number. A closure can also be assigned to a variable, as shown below:

let addOne = { (number: Int) -> Int in
return number + 1
}
let num = 3
let afterClosureCall = addOne(num)
print(afterClosureCall)

Closure as a function parameter

A closure can also be used as a function parameter. The following code example clarifies how it's used.

Code example

func performAction(number: Int, action: (Int) -> Int) -> Int {
return action(number)
}
let num = 3
let newNum = performAction(number: num, action: { (num: Int) -> Int
in
return num + 10
})
print("The first closure adds 10 and returns", newNum)
//short-hand form
let anotherNum = performAction(number: num, action: { num in num * num })
print("The second closure squares the number and returns", anotherNum)

Explanation

  • Lines 1–3: We define a function performAction that takes an Int and closure as arguments. We also define the argument and return type of the closure.

  • Lines 6–10: We call performAction with a closure that adds ten to num and returns that number.

  • Line 13: We call performAction again with an inline closure, but this time a short-hand form is used. Closures can be written this way as well, since they can infer the type and return implicitly.

Trailing closures

A trailing closure is a closure expression that is written after the brackets of the function call. This is useful, especially in cases where the function call is long, to keep the code organized. There can be multiple trailing closures.

Code example

let n = 3
let newN = performAction(number: n) { num in
num * 2
}
print(newN)

Explanation

Considering the performAction function defined in the earlier example, a trailing closure can be called as shown in this example. Here, the closure expression doubles the number and returns it.

Autoclosures

Autoclosures are closure expressions that are not enclosed in curly braces {}. They can only contain a single expression. They do not take any arguments and return the value of that expression. The parameter type of a function that accepts an autoclosure has to be marked with the keyword @autoclosure.

Code example

func callThrice(closure: @autoclosure () -> ()) {
for _ in 1...3 {
closure()
}
}
callThrice(closure: print("Hello there!"))

Explanation

  • Lines 1–5: We define a function callThrice that takes an autoclosure as an argument and calls it three times in a for loop.

  • Line 7: We call the function callThrice with the closure expression print("Hello there!")

Escaping closures

Escaping closures are passed as function arguments after the function returns. One of the ways we can achieve this is by storing the closure in a variable defined outside the function.

Code example

var escapingClosures: [() -> Void] = []
func functionWithClosure(closure: @escaping () -> Void) {
escapingClosures.append(closure)
}
functionWithClosure(closure: {
print("Hello there!")
})
escapingClosures[0]()

Explanation

In the above example, the function is defined with the @escaping keyword. The function containing the closure is called on line 6, but it does not print anything since the closure is escaping. The closure is later called separately on line 10, which prints "Hello there!" on the screen.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved