Open In App

Closures in Swift

Last Updated : 17 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

In Swift, Closures are known as self-contained blocks of functionality that can be passed around and used inside your code. They are quite similar to blocks in C and Objective-C and to lambdas in other programming languages. Closures can also capture and store references to any constants and variables from the context in which they are defined. 

Closures

Closures in Swift are first-class citizens, which means they can be treated like any other type (such as strings, integers, and classes). They are often used for functional programming patterns, such as mapping and filtering arrays, and for asynchronous programming. They can also be passed as arguments to functions and can be returned from functions as well. Closures are a powerful and flexible feature of Swift, and they are used extensively in the language’s standard library and APIs.

Syntax:

{ (parameters) -> return type in

   statements }

Example:

Swift




// Swift program to illustrat closures
import Swift
  
// Printing hello world using closure
let greet = {
    print("Hello, world!")
}
  
greet()


Output: 

Hello, world!

In this example, greet is a closure that simply prints a greeting to the console. You can call the closure by using its name followed by parentheses, just like a function.

Here is an example of how to use closures in Swift, with explanations of each step and some screenshots of the output:

Define a Closure

To define a closure in Swift, you use the {} syntax and include the closure’s parameters, return type (if any), and body. Here is an example of a closure that takes two integers and returns their product:

let multiply: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in

 return a * b

}

Call the Closure

To call a closure, you simply use its name followed by parentheses and any necessary arguments. For example:

let result = multiply(5, 7)  // result is 35

Use the Closure in a Function

You can also pass closure as an argument to a function. Here is an example of a function that takes a closure as an argument and uses it to perform a calculation:

func performCalculation(a: Int, b: Int, operation: (Int, Int) -> Int) -> Int {

 return operation(a, b)

}

let result = performCalculation(a: 5, b: 7, operation: multiply)  // result is 35

Example:

Swift




// Swift program to illustrate how to use the closure in a function
let multiply: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
    return a * b
}
  
// Creating a function
func performCalculation(a: Int, b: Int, operation: (Int, Int) -> Int) -> Int {
    return operation(a, b)
}
  
// Calling function
let result = performCalculation(a: 5, b: 7, operation: multiply) 
  
// Displaying output
print(result)


Output:

35

Inferring Type From Context

In Swift, you can often omit the type of a variable or constant when it can be inferred from the context. Swift may infer the types of a method’s parameters and the type of value it returns because the sorting closure is supplied as an argument to the method. A function of the form (String, String) -> Bool must be used as the argument because the sorted(by:) method is being called on an array of strings. This implies that the definition of the closure expression does not require the writing of the (String, String) and Bool types. When providing closure to a function or method as an inline closure expression, it is always feasible to deduce the parameter types and return types. As a result, whenever an inline closure is used as a function or method argument, you never need to write it in its entirety. 

Example:

Swift




// Swift program to create a function to prints "hello world"
func concatenate(_ strings: [String]) -> String 
{
    return strings.joined(separator: " ")
}
  
let words = ["hello", "world"]
  
// The type of 'sentence' is inferred to be String
let sentence = concatenate(words)  
print(sentence) 


Output:

hello world

In the example above, the type of the sentence constant is inferred to be a String because it is the result of calling the concatenate(_:) function, which returns a string. The type of the word constant is inferred to be [String] because it is initialized with an array literal that contains only strings.

Shorthand Argument Names

Shorthand argument names refer to the arguments of a function or closure. Shorthand argument names are automatically provided to you by Swift and are a convenient way to refer to the arguments of a function or closure in a concise way. You can omit the closure’s argument list from its definition if you use these abbreviated argument names in your closure expression. The expected function type is used to infer the type of the shorthand argument names, and the closure’s maximum number of arguments is determined by the highest shorthand argument you use.

Example:

Swift




// Swift program to shorthand argument names in a function
  
// Function to print "Hello, GeeksforGeeks!"
func sayHello(to name: String
{
    print("Hello, \(name)!")
}
  
sayHello(to: "GeeksforGeeks")  


In the example above, the sayHello(to:) function takes a single argument called name of type String. The to label is used to distinguish the argument from other arguments that may have the same name. 

Output:

Hello, GeeksforGeeks!

Operator Methods

Operator methods to implement custom behavior for existing operators. Operator methods are special methods that have a symbolic operator as their name. You can define operator methods for most of the standard operators in Swift, such as the assignment operator =, the arithmetic operators +, -, *, /, and %, and the comparison operators ==, !=, >, <, >=, and <=.

Example:

Here’s an example with output to show you how the custom Vector2D type works with the defined operator methods:

Swift




// Swift program to show how the custom Vector2D type works
// with the defined operator methods
import Swift
  
struct Vector2D {
    var x: Double
    var y: Double
}
  
// Function to create custom Vector2D
extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
      
    static func - (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x - right.x, y: left.y - right.y)
    }
}
  
// Define values
let vector1 = Vector2D(x: 3.0, y: 5.0)
let vector2 = Vector2D(x: 2.0, y: 4.0)
let sum = vector1 + vector2
let difference = vector1 - vector2
  
// Print result
print("vector1: (\(vector1.x), \(vector1.y))")
print("vector2: (\(vector2.x), \(vector2.y))")
print("sum: (\(sum.x), \(sum.y))")
print("difference: (\(difference.x), \(difference.y))")


Output:

vector1: (3.0, 5.0)
vector2: (2.0, 4.0)
sum: (5.0, 9.0)
difference: (1.0, 1.0)

Trailing Closures

A trailing closure is a closure expression that is written after the function call’s parentheses, outside of the parentheses. It can be used when the closure is the only or the last argument of the function. When the closure is so long that it cannot be written inline on a single line, trailing closures are most helpful. Swift’s Array type, for instance, provides a map(_:) method that accepts a closure expression as its sole parameter. The closure delivers an alternative mapped value for each item in the array for which it is called once. By including code in the closure you supply to map(_:), you can specify the type of the mapping and the returned value.

The map(_:) method returns a new array containing all of the new mapped values, in the same order as their corresponding values in the original array, after applying the specified closure to each array element. Trailing closures can make your code more concise. If the closure is the last argument of the function, you can omit the argument label and the parentheses for the closure.

Example:

Swift




// Swift program with trailing closure
  
// Function with a trailing closure
func transform(number: Int, closure: (Int) -> Int) -> Int {
    return closure(number)
}
  
// Call the function with a trailing closure
let result = transform(number: 5) { (number: Int) -> Int in
    return number * 2
}
  
// Print output
print(result)


Output:

10

In this example, the transform function takes an Int as an argument and a closure that takes an Int and returns an Int. The function returns the result of calling the closure on the input number. We can call the transform function using a trailing closure that multiplies the input number by 2. The result of the function call is 10.

Capturing Values

A closure can capture values from the surrounding context in which it is defined. This allows the closure to access and modify variables and constants outside of its own scope. To capture a value in a closure, you simply reference the value by name inside the closure.

Example:

Swift




// Swift program to capture values
  
// Function to capture values
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
      
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}
let incrementByTwo = makeIncrementer(forIncrement: 2)
  
// Print the function output
print(incrementByTwo())  // 2
print(incrementByTwo())  // 4
print(incrementByTwo())  // 6


Output:

2
4
6

In this example, the makeIncrementer(forIncrement:) function defines a closure called incrementer that increments a running total by a specified amount. The incrementer closure captures the runningTotal and amount variables from the surrounding context.

When you call the makeIncrementer(forIncrement:) function, it returns the incrementer closure. You can then call the closure to increment the running total, the incrementByTwo constant is assigned the return value of makeIncrementer(forIncrement: 2), which is the incrementer closure. Each time you call the incrementByTwo closure, it increments the running total by 2 and returns the new value.

Here is a summary of some key points about closures in Swift:

  • A closure is a self-contained block of code that can be passed around and used in your code.
  • Closures can capture values from the surrounding context in which they are defined.
  • Closures can be passed as arguments to functions and be returned as values from functions.
  • You can use trailing closure syntax to make your code more concise when the closure is the last argument of a function.


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads