- Swift Tutorial
- Swift - Home
- Swift - Overview
- Swift - Environment
- Swift - Basic Syntax
- Swift - Variables
- Swift - Constants
- Swift - Literals
- Swift - Comments
- Swift Operators
- Swift - Operators
- Swift - Arithmetic Operators
- Swift - Comparison Operators
- Swift - Logical Operators
- Swift - Assignment Operators
- Swift - Bitwise Operators
- Swift - Misc Operators
- Swift Advanced Operators
- Swift - Operator Overloading
- Swift - Arithmetic Overflow Operators
- Swift - Identity Operators
- Swift - Range Operators
- Swift Data Types
- Swift - Data Types
- Swift - Integers
- Swift - Floating-Point Numbers
- Swift - Double
- Swift - Boolean
- Swift - Strings
- Swift - Characters
- Swift - Type Aliases
- Swift - Optionals
- Swift - Tuples
- Swift - Assertions and Precondition
- Swift Control Flow
- Swift - Decision Making
- Swift - if statement
- Swift - if...else if...else Statement
- Swift - if-else Statement
- Swift - nested if statements
- Swift - switch statement
- Swift - Loops
- Swift - for in loop
- Swift - While loop
- Swift - repeat...while loop
- Swift - continue statement
- Swift - break statement
- Swift - fall through statement
- Swift Collections
- Swift - Arrays
- Swift - Sets
- Swift - Dictionaries
- Swift Functions
- Swift - Functions
- Swift - Nested Functions
- Swift - Function Overloading
- Swift - Recursion
- Swift - Higher-Order Functions
- Swift Closures
- Swift - Closures
- Swift-Escaping and Non-escaping closure
- Swift - Auto Closures
- Swift OOps
- Swift - Enumerations
- Swift - Structures
- Swift - Classes
- Swift - Properties
- Swift - Methods
- Swift - Subscripts
- Swift - Inheritance
- Swift-Overriding
- Swift - Initialization
- Swift - Deinitialization
- Swift Advanced
- Swift - ARC Overview
- Swift - Optional Chaining
- Swift - Error handling
- Swift - Concurrency
- Swift - Type Casting
- Swift - Nested Types
- Swift - Extensions
- Swift - Protocols
- Swift - Generics
- Swift - Access Control
- Swift - Function vs Method
- Swift - SwiftyJSON
- Swift - Singleton class
- Swift Random Numbers
- Swift Opaque and Boxed Type
- Swift Useful Resources
- Swift - Compile Online
- Swift - Quick Guide
- Swift - Useful Resources
- Swift - Discussion
Swift - Closures
What is Closures in Swift?
Closures are self-contained blocks of functionalities that can be used inside the program and perform the specified task. Closures are similar to blocks in Objective-C or anonymous functions in other programming languages. They are allowed to capture and store the references to the variables or constants from the context in which they are defined. Also, they can access the values of these constants or variables even if they are outside the original scope.
Closure in the Swift has three forms −
Global Functions − They are closures with a name that do not capture any value.
Nested Function − A function defined inside another function. They have names and can capture values from the enclosing function.
Closure Expression − Using this we can write closure more concisely. We can write unnamed closures that capture values from the adjacent block.
Closures Expression
Closure expression provides a way to write inline closure or inline and unnamed functions. It supports various short, optimized and focused syntaxes to write closure without losing its clarity. So first of all we will see the basic syntax of closure then we will move to the other expression syntaxes supported by Swift −
Inferring parameter and return value types from context.
Implicit returns from single-expression closures.
Shorthand argument names
Operator methods
Defining and Calling basic closure
In Swift, we can define a closure simply by using curly braces{}. These curly braces contain the closure parameters, return type(if available), the in keyword to separate the parameter and return type with the body, and the body of the closure. The parameters of closure can be regular, in-out and variadic parameters, but they do not contain default values. Tuples can also used as a parameter and return types in closures. And we can call a closure by passing value for the parameters(if available).
Syntax
Following is a generic syntax to define closure which accepts parameters and returns a data type −
{(parameters) -> return type in // body of closure }
Following is the syntax for calling the closure.
closure(parameters)
Example
Swift program to demonstrate a closure without parameters.
// Creating a Closure let studname = { print("Welcome to Swift 4 Closures") } // Calling a closure studname()
Output
It will produce the following output −
Welcome to Swift 4 Closures
Example
Swift program to demonstrate a closure with parameters.
// Closure with parameters let divide = {(val1: Int, val2: Int) -> Int in return val1 / val2 } // Calling closure let result = divide(200, 20) print (result)
Output
It will produce the following output −
10
Inferring type from context
A closure can also pass as an inline closure expression in the function or method, so we are allowed to infer the types of its parameters and the return value. That means we are not explicitly required to write the type of parameter passed in the closure and the type of value returned by the closure, the compiler will automatically infer the type of the closure from the context in which it is used.
Example
Swift program to pass a closure as a parameter in the function.
// Define an array of String let myValues = ["Mohina", "Suman", "Mohit"] // Use the 'map' function to add the given string in all the elements of the array /* The type of closure is inferred according to the fact that 'map()' is applied to an array of strings. So here the closure adds a specified string to each element hence the inferred type of the closure is (String) -> String*/ let newArray = myValues.map { $0 + " Hey" } print(newArray)
Output
It will produce the following output −
["Mohina Hey", "Suman Hey", "Mohit Hey"]
Implicit Return From Single-Expression Closure
In Closure, a single expression can implicitly return an expression without explicitly using the return keyword. Or we can say that a closure can return an expression without specifying the return type if it contains only one statement. It makes syntax more straightforward and readable.
Example
Swift program to implicitly return expression from single expression closure.
// Single line closure without return type let add: (Int, Int) -> Int = { a, b in a + b } let output = add(5, 6) print("Addition:", output)
Output
It will produce the following output −
Addition: 11
Shorthand Argument Names
While working with inline closure we are allowed to write the values of the closure's arguments by the names $0, $1, $2, and so on, instead of naming them. It is the shortest way to express arguments in the closer. Where $0 refers to the first parameter, $1 refers to the second parameter, $2 refers to the third parameter and so on.
If we are using these shorthand argument names, then we can remove the closure argument list from the definition section. The compiler will automatically infer the type of the arguments from the expected function type. We can also remove in keyword because the shorthand argument is defined in the expression body.
Example
Swift program to demonstrate shorthand argument names in closure.
// Creating a closure var shorthand: (String, String) -> String // Assigning the second parameter and discarding the first parameter shorthand = { $1 } // Calling the closure with two arguments will return the second parameter print(shorthand("100", "200"))
Output
It will produce the following output −
200
Operators Methods
Swift provides an easy way to access the members by just providing operator functions as closures. Or we can say that using closure we can define the behaviour of the operators by overloading them.
Example
Swift program to demonstrate operator method in closure.
// Define a custom operator method for addition numbers func + (left: (Double, Double), right: (Double, Double)) -> (Double, Double) { return (left.0 + right.0, left.1 + right.1) } // Using the custom operator in a closure let addNumbers: ((Double, Double), (Double, Double)) -> (Double, Double) = { $0 + $1 } let num1 = (3.0, 3.0) let num2 = (5.0, 2.0) // Adding the values using addNumbers closure let result = addNumbers(num1, num2) print("Resultant Sum: \(result)")
Output
It will produce the following output −
Resultant Sum: (8.0, 5.0)
Trailing Closures
Trailing closures are the special type of closures in Swift. When a closure is defined outside of the function parentheses() especially when the closure is the last argument of the function then such type of closure is known as trailing closure.
Such types of closures are generally used when the closure is long and it is impossible to write it inline. If the function contains only closure as an argument, then while calling the function or method we can remove parentheses(), for example, names.map{$1 = $0}.
Syntax
Following is the syntax for the trailing function −
// Function that takes closure func functionName(closure:()->void){ // Function body } // Calling function without trailing closure functionName(closure:{// closure body}) // Calling function with trailing closure functionName(){// closure body}
Example
Swift program to demonstrate trailing closure.
// Function to operate on two numbers using a trailing closure func operation(_ x: Int, _ y: Int, op: (Int, Int) -> Int) -> Int { return op(x, y) } // Using trailing closure to add two numbers let res = operation(8, 9) { (a, b) in return a + b } print("Sum: \(res)")
Output
It will produce the following output −
Sum: 17
Trailing functions are common among high-order functions like map, filter or sort, where the closure works as a callback or transformation.
Example
Swift program to demonstrate trailing closure in high-order function.
// Array of string let names = ["Mohan", "Mohit", "Roy", "Suman"] // Calling map() function with trailing function let lowercaseNames = names.map { $0.lowercased() } // Displaying the names in lowercased print(lowercaseNames)
Output
It will produce the following output −
["mohan", "mohit", "roy", "suman"]
A single function can have multiple trailing closures, where we can remove the argument label of the first trailing closure and label the remaining trailing closures.
Example
Swift program to demonstrate multiple trailing closures in a function.
// Function with multiple trailing closures func Operations(_ x: Int, _ y: Int, op1: (Int, Int) -> Int, op2: (Int, Int) -> Int) -> (Int, Int) { let result1 = op1(x, y) let result2 = op2(x, y) return (result1, result2) } // Using multiple trailing closures var output = Operations(11, 6, op1: { $0 + $1 }, op2: { $0 * $1 }) print(output)
Output
It will produce the following output −
(17, 66)
Capturing Values and Reference Types
In Swift, capturing constants and variable values is done with the help of closures. It further refers to and modifies the values for those constants and variables inside the closure body even though the original scope in which the variable or constant is defined, is no longer exists.
While assigning a function or closure to a constant or a variable, we are setting that constant or variable as a reference to that function or closure. That means if we assign a closure to two constants or variables, then both the constants or variables refer to the same closure.
Example
func calcDecrement(forDecrement total: Int) -> () -> Int { var overallDecrement = 100 func decrementer() -> Int { overallDecrement -= total print(overallDecrement) return overallDecrement } return decrementer } let decrem = calcDecrement(forDecrement: 18) print(decrem()) print(decrem()) print(decrem())
Output
It will produce the following output −
82 82 64 64 46 46
Every time the outer function calcDecrement is called it invokes the decrementer() function, decrements the value by 18 and returns the result with the help of outer function calcDecrement. Here calcDecrement acts as a closure.
Even though the function decrementer() does not have any arguments closure by default refers to variables 'overallDecrement' and 'total' by capturing its existing values. The copy of the values for the specified variables is stored with the new decrementer() function. Swift handles memory management functions by allocating and deallocating memory spaces when the variables are not in use.