Swift Closures

In Swift, a closure is a special type of function without the function name. For example,

{
  print("Hello World")
}

Here, we have created a closure that prints Hello World.

Before you learn about closures, make sure to know about Swift Functions.


Swift Closure Declaration

We don't use the func keyword to create closure. Here's the syntax to declare a closure:

{ (parameters) -> returnType in
   // statements
}

Here,

  1. parameters - any value passed to closure
  2. returnType - specifies the type of value returned by the closure
  3. in (optional) - used to separate parameters/returnType from closure body

Let's see an example,

var greet = {
  print("Hello, World!")
}

Here, we have defined a closure and assigned it to the variable named greet. Statement enclosed inside the {} is the closure body.

To execute this closure, we need to call it. Here's how we can call the closure

// call the closure
greet()

The closure simply prints the text Hello World.

Note: This closure doesn't have any parameters and return type.


Example: Swift Closure

// declare a closure
var greet = {
  print("Hello, World!")
}

// call the closure
greet()

Output

Hello, World!

In the above example, we have defined a closure and assigned it to the variable named greet.

When we call the closure, the print() statement inside the closure is executed.


Closure Parameters

Similar to functions, a closure can also accept parameters. For example,

// closure that accepts one parameter
let greetUser = { (name: String)  in
    print("Hey there, \(name).")
}

// closure call
greetUser("Delilah")

Output

Hey there, Delilah.

In the above example, we have assigned a closure to the greetUser variable.

Inside the closure, (name: String) specifies that the closure accepts the String type parameter named. Notice that we have used in to separate closure parameter with body.

Also, notice the call of closure

greetUser("Delilah")

Here, we have passed a string value "Delilah" to our closure.

And finally, the statement inside the closure is executed.

Note: Unlike function, we call the closure without mentioning the parameter name.


Closure That Returns Value

A Swift closure may or may not return a value. If we want our closure to return some value, we need to mention it's return type and use the return statement. For example,

// closure definition
var findSquare = { (num: Int) -> (Int) in
  var square = num * num
  return square
}

// closure call
var result = findSquare(3)

print("Square:",result)

Output

Square: 9

In the above example, we have defined a closure that returns the square of a number. Notice the closure definition,

var findSquare = { (num: Int) -> (Int) in
  ... 
  return square
}

Here, (num: Int) -> (Int) indicates that the closure

  • (num: Int) - indicates the parameter of integer type
  • -> (Int) - represents the closure return value of Int type
  • return square - return statement inside the closure

The returned value is stored in the result variable.


Closures as Function Parameter

In Swift, we can create a function that accepts closure as its parameter.

// define a function
func grabLunch(search: () -> ()) {
  …
  // closure call
  search()  
}

Here,

  • search - function parameter
  • () -> () - represents the type of the closure
  • search() - call closure from the inside of the function.

Now, to call this function, we need to pass a closure as its argument

// function call
grabLunch(search: {
  print("Alfredo's Pizza: 2 miles away")
})

Example: Closure as function parameter

// define a function and pass closure
func grabLunch(search: ()->()) {
  print("Let's go out for lunch")

  // closure call
  search()
}

// pass closure as a parameter
grabLunch(search: {
   print("Alfredo's Pizza: 2 miles away")
})

Output

Let's go out for food
Alfredo's Pizza: 2 miles away

Trailing Closure

In trailing closure, if a function accepts a closure as its last parameter,

// function definition
func grabLunch(message: String, search: ()->()) {
  ...
}

We can call the function by passing closure as a function body without mentioning the name of the parameter. For example,

// calling the function
grabLunch(message:"Let's go out for lunch")  {
  // closure body
}

Here, everything inside the {...} is a closure body.


Example: Trailing Closure

func grabLunch(message: String, search: ()->()) {
   print(message)
   search()
}

// use of trailing closure
grabLunch(message:"Let's go out for lunch")  {
  print("Alfredo's Pizza: 2 miles away")
}

Output

Let's go out for lunch
Alfredo's Pizza: 2 miles away

In the above example, the grabLunch() function accepts a closure search: () -> (). Here, closure is the last parameter of the function.

Hence, we have called the function by passing the closure argument as function definition.

grabLunch(message:"Let's go out for lunch")  {
  print("Alfredo's Pizza: 2 miles away")
}

Autoclosure

While calling a function, we can also pass the closure without using the braces {}.For example,

// using {}
display(greet:{
  print("Hello World!")
}

// without using {}
display(greet: print("Hello World!"))

To pass the closure argument without using braces, we must use the @autoclosure keyword in function definition. For example,

func display(greet: @autoclosure () -> ()) {
 ...
}

Here, the @autoclosure automatically adds curly braces.


Example: Autoclosure

// define a function with automatic closure
func display(greet: @autoclosure () -> ()) {
 greet()
}

// pass closure without {}
display(greet: print("Hello World!"))

Output

Hello World!

Note: We cannot pass arguments to an autoclosure. If we try to do so we'll get the error message as: argument type of @autoclosure parameter must be '()'.

Did you find this article helpful?