(Swift for Beginners)
Swift Closures
In this article, you’ll learn what is a closure, syntax, types of closures in Swift with examples.
In the article Swift functions, we created a function using func
keyword. However, there is another special type of function in Swift, known as closures that can be defined without using keyword func
and a function name.
Like functions, closures can accept parameters and return values. It also contains a set of statements which executes after you call it and can be assigned to a variable/constant as functions.
Closures are mainly used for two reasons:
- Completion blocks
Closures help you to be notified when some task has finished its execution. See Closure as a completion handler to learn more about it. - Higher order functions
Closures can be passed as an input parameters for higher order functions. A higher order function is just a type of function that accepts function as an input and returns value of type function as output.
For this purpose it’s better to use closures in replacement of function because closure omits the func keyword and function name that makes the code more readable and short.
Syntax of closure
Closure expression syntax has the following general form:
{ (parameters) -> return type in statements }
Notice the use of in
keyword after the return type. The in
keyword is used to separate the return Type and statements inside the closure. The closure accepts parameters and can return value. Lets learn to create your own closures with below examples:
Example 1: Simple Closure
let simpleClosure = {
}
simpleClosure()
In the above syntax, we have declared a simple closure { }
that takes no parameters, contains no statements and does not return a value. This closure is assigned to the constant simpleClosure.
We call the closure as simpleClosure()
, but since it doesn’t contain any statements, the program does nothing.
Example 2: Closure that contains statements
let simpleClosure = {
print("Hello, World!")
}
simpleClosure()
When you run the above program, the output will be:
Hello, World!
In the above program, you have defined a closure simpleClosure. The type of the simpleClosure is inferred to be of () -> ()
because it doesn’t accept parameter and does not return a value.
If you want to explicitly defined the type of the closure, you can do so as let simpleClosure:() -> ()
.
Unlike the first example, calling the closure as simpleClosure()
executes the print()
statement inside it. This prints Hello, World!
in the console.
Example 3: Closure that accepts parameter
let simpleClosure:(String) -> () = { name in
print(name)
}
simpleClosure("Hello, World")
When you run the above program, the output will be:
Hello, World!
In the above program, the type of closure (String) -> ()
states that the closure takes an input of type String
but does not return value.You can use the value passed inside the statements of the closure by placing a parameter name name followed by in
keyword.
Remember the use of in
keyword is to separate the parameter name with the statements. Since the closure accepts a String
, you need to pass the string while you call the closure as simpleClosure("Hello, World")
. This executes statement inside the closure and outputs Hello, World! in the console.
Example 4: Closure that returns value
A closure can also return value, as functions. If you need to return value from closure, you must explicitly add the type to return inside braces ()
which is followed by ->
.
let simpleClosure:(String) -> (String) = { name in
let greeting = "Hello, World! " + "Program"
return greeting
}
let result = simpleClosure("Hello, World")
print(result)
When you run the above program, the output will be:
Hello, World! Program
In the above program, we have defined type as simpleClosure: (String) -> (String)
because Swift cannot automatically infer the closure that returns a value. The type (String) -> (String)
states that the closure takes an input of type String
and also returns a value of type String
.
The closure also returns a value using the return keyword as return greeting
and the returned value can be assigned in a variable/constant as let result =
as we have learned in Swift functions.
Example 4: Passing Closures as a function parameter
We can also pass closure as a parameter to a function as:
func someSimpleFunction(someClosure:()->()) {
print("Function Called")
}
someSimpleFunction(someClosure: {
print("Hello World! from closure")
})
When you run the above program, the output will be:
Function Called
In the above program, the function accepts a closure of type ()->()
i.e takes no input and doesn’t return any value.
Now when calling the function someSimpleFunction()
, you can pass the closure { print("Hello World! from closure") }
as a parameter.
The function call triggers the print("Function Called")
statement inside the function which outputs Function Called in the screen. However, the closure statement is not executed because you have not made the call to the closure.
You can call the closure simply as someClosure()
which executes the statement inside the closure.
func someSimpleFunction(someClosure:()->()) {
print("Function Called")
someClosure()
}
someSimpleFunction(someClosure: {
print("Hello World! from closure")
})
When you run the above program, the output will be:
Function Called Hello World! from closure
Trailing Closure
If a function accepts a closure as its last parameter, the closure can be passed similar to a function body between { }
. This type of closure written outside of function call parentheses is known as trailing closure.
The above program can be rewritten using trailing closure as:
Example 5: Trailing closure
func someSimpleFunction(msg:String, someClosure:()->()) {
print(msg)
someClosure()
}
someSimpleFunction(msg:"Hello Swift Community!") {
print("Hello World! from closure")
}
When you run the above program, the output will be:
Hello Swift Community! Hello World! from closure
In the above program, function someSimpleFunction()
accepts a closure as a final parameter. So, while calling the function, instead of passing the closure as an argument, we have used trailing closure.
As you can see, in the function call
someSimpleFunction(msg:"Hello Swift Community!") { print("Hello World! from closure") }
closure { print("Hello World! from closure") }
looks like the body of a function rather than function argument, but remember it’s still an argument to the function.
Because of trailing closure, we haven’t specified the parameter name for the closure which makes the code shorter and more readable.
It is not mandatory to write trailing closure. However, it is recommended for readability purpose when a function accepts a closure as a final argument.
AutoClosure
A closure which is marked with @autoclosure
keyword is known as autoclosure. @autoclosure
keyword creates an automatic closure around the expression by adding a {}
. Therefore, you can omit braces {}
when passing closures to a function.
The main advantage of using autoclosure is that you don’t need to wrap the expression in curly braces {}
when calling closures.
Let’s see this in example.
Example 6: Closure without @autoclosure
func someSimpleFunction(someClosure:()->(), msg:String) {
print(msg)
someClosure()
}
someSimpleFunction(someClosure: ({
print("Hello World! from closure")
}), msg:"Hello Swift Community!")
When you run the above program, the output will be:
Hello Swift Community! Hello World! from closure
In the above program, we have declared a function that accepts a normal closure ()->()
as the parameter of the function someSimpleFunction()
. You can see, when calling the function, you need to add {}
around the function parameter as
someClosure: ({ print("Hello World! from closure") })
We can rewrite the above program using autoclosure as:
Example 7: Autoclosure
func someSimpleFunction(someClosure: @autoclosure ()->(), msg:String) {
print(msg)
someClosure()
}
someSimpleFunction(someClosure: (print("Hello World! from closure")), msg:"Hello Swift Community!")
When you run the above program, the output will be:
Hello Swift Community! Hello World! from closure
In the above program, we have marked the closure ()->()
to be of type autoclosure with @autoclosure
attribute. So, you don’t have to add { }
around the function parameter as someClosure: (print("Hello World! from closure"))
.
Autoclosure with arguments and return value
Like normal closures, you can pass arguments to and return value from an autoclosure. However, even if you pass the arguments, they get ignored and cannot be used inside the closure. This is because you cannot define the parameter to use it as { arg in }
.
Therefore, it is recommended to create autoclosures that don’t take arguments but can return value. Value is the expression that’s wrapped inside of it. Let’s see this in below example.
Example 8: Autoclosure with return value
func someSimpleFunction(_ someClosure:@autoclosure ()->(String)) {
let res = someClosure()
print(res)
}
someSimpleFunction("Good Morning")
When you run the above program, the output will be:
Good Morning
In the above program, we’ve defined a function that takes no parameter but returns a String
(()->(String)
). We passed the autoclosure “Good Morning” to the function. This is also the return value of the closure.
So, when we called someClosure()
inside the function, it returned the value Good Morning.
Example 9: Autoclosure with arguments
func someSimpleFunction(_ someClosure:@autoclosure (String)->(String)) {
let res = someClosure("Hello World")
print(res)
}
someSimpleFunction("Good Morning")
When you run the above program, the output will be:
Good Morning
In the above program ,we have defined a function that takes an autoclosure. The closure takes a value of type String
and also returns value of type String
.
Like the previous example, we pass autoclosure “Good Morning” to the function, which is the return value of the closure.
So, even though autoclosure is called as someClosure("Hello World")
, it cannot accept any parameters, it still returns and prints Good Morning.
Escaping vs No Escaping Closures
No Escaping Closure
A closure is said to be no escaping when the closure is passed as an argument to the function, and is called before the function returns. The closure is not used outside of the function.
In Swift, all closure parameters are no escaping by default. The concept of escaping and no escaping closure is for compiler optimization.
Example 10: No escaping closure
func testFunctionWithNoEscapingClosure(myClosure:() -> Void) {
print("function called")
myClosure()
return
}
//function call
testFunctionWithNoEscapingClosure {
print("closure called")
}
When you run the above program, the output will be:
function called closure called
In the above example, the closure is said to be no escaping because the closure myClosure()
is called before the function returns and closure is not used outside the body of the function.
Escaping Closure
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns or the closure is used outside of the body of the function.
Example 11: Escaping Closure
var closureArr:[()->()] = []
func testFunctionWithEscapingClosure(myClosure:@escaping () -> Void) {
print("function called")
closureArr.append(myClosure)
myClosure()
return
}
testFunctionWithEscapingClosure {
print("closure called")
}
When you run the above program, the output will be:
function called closure called
In the above example, we have declared a variable closureArr that can storeanarray of closures of type ()->()
.
Now, if we append the closure myClosuredefined within the scope of the function to the closureArr defined outside of the function, the closure myClosure needs to escape the body of the function.
So, the closure needs to be escaping and marked with @escaping
keyword.
Example 12: No escaping closure
In the above No Escaping Closure section, we described a closure needs to be no escaping if the closure is called before the function returns. So, if a closure calls after the function returns, that should be escaping, right?
Lets test this with an example:
func testFunctionWithNoEscapingClosure(myClosure:() -> Void) {
return
myClosure()
}
The above code returns warning because statements appearing after the return statement(in our case myClosure()
) does not execute because the return statement transfers the control of the program to the function caller.
So, how do we test so that the closure is called after the function returns. It can be done if the closure call is placed inside an asynchronous operation.
Synchronous operation waits for the operation to complete/finish before moving to the next statement (top to Bottom order). And, Asynchronous moves to the next statement even if the current operation hasn’t completed.
Therefore, statements that is placed inside an asynchronous operation may execute later at some point.
func testFunctionWithNoEscapingClosure(myClosure:@escaping () -> Void) {
DispatchQueue.main.async {
myClosure()
}
return
}
In the above program, DispatchQueue.main.async
runs the block of code asynchronously. So, now. the closure call myClosure()
may happen even after the function returns. So, the closure needs to be escaping and is marked with @escaping
keyword.
Closure as a completion handler
Completion handler are callbacks/notifications that allows you to perform some action when a function completes its task.
Completion handler are mostly used in asynchronous operations so that the caller can know when the operation has completed to perform some action after the completion of the operation.
Example 13: Closure as a completion handler
func doSomeWork(completion:()->()) {
print("function called")
print("some work here")
print("before calling callback")
completion()
print("after calling callback")
}
doSomeWork(completion: {
print("call back received")
})
print("Other statements")
When you run the above program, the output will be:
function called some work here before calling callback call back received after calling callback Other statements
The above program can also be rewritten using trailing closure as:
Example 14: Trailing Closure as a completion handler
func doSomeWork(completion:()->()) {
print("function called")
print("some work here")
print("before calling callback")
completion()
print("after calling callback")
}
doSomeWork() {
print("call back received")
}
print("Other statements")
How completion handler works?

Here are the execution steps:
doSomeWork()
calls the function which executes the statement inside the functionprint("function called")
outputs function called in the console.- You may perform some work inside the function. For now just a
print("some work here")
statement that outputs some work herein the console. - A simple call to the closure as
completion()
will send the callback and transfers the control of the program to the statements inside the closure.
So,print("call back received")
executes which outputs call back received in the console. - After that the program control again returns to the closure call, and executes statement
print("after calling callback")
which outputs after calling callback in the console. - After the statements inside the function executes, program transfers the control to the function call
doSomeWork()
and then executes the next statementprint("Other statements")
which outputs Other statements in the console.
Let’s see one more practical example to use closure as a completion handler.
Example 11: Closure as a completion handler
var closeButtonPressed = false
func codeinPlayground(completion:(String)->()) {
print("Code, Take a Nap and Relax")
if closeButtonPressed {
completion("Close the playground")
}
}
codeinPlayground { (msg) in
print(msg)
}
When you run the above program, the output will be:
<preCode, Take a Nap and RelaxIn the above program, we have declared a variable closeButtonPressed that mocks if user has tapped close button on playground. Think if you press the close button, variable closeButtonPressed will be true
.
The function codeinPlayground
accepts a closure as an argument. The closure completion
accepts a String
but does not return a value. Since the closeButtonPressed
is assigned false
, statement inside if statement does not execute and closure is not called.
Now, if you assign the closeButtonPressed to true
(i.e., when user pressed close button) as var closeButtonPressed = true
, statements inside if executes and closure is called.
When you assign true to variable closeButtonPressed, the output will be:
Code, Take a Nap and Relax Close the playground
Here, we have used closure as a completion handler because when user taps the close button, we don’t want to execute statements inside the function codeinPlayground
, instead complete its execution by calling the closure completion("Close the playground")
.
This way we get a chance to handle all the final events related to the function inside the statements of the closure. In our case we have output the message in console as print(msg)
.
Disclaimer: The information and code presented within this recipe/tutorial is only for educational and coaching purposes for beginners and developers. Anyone can practice and apply the recipe/tutorial presented here, but the reader is taking full responsibility for his/her actions. The author (content curator) of this recipe (code / program) has made every effort to ensure the accuracy of the information was correct at time of publication. The author (content curator) does not assume and hereby disclaims any liability to any party for any loss, damage, or disruption caused by errors or omissions, whether such errors or omissions result from accident, negligence, or any other cause. The information presented here could also be found in public knowledge domains.
Learn by Coding: v-Tutorials on Applied Machine Learning and Data Science for Beginners
Latest end-to-end Learn by Coding Projects (Jupyter Notebooks) in Python and R:
All Notebooks in One Bundle: Data Science Recipes and Examples in Python & R.
End-to-End Python Machine Learning Recipes & Examples.
End-to-End R Machine Learning Recipes & Examples.
Applied Statistics with R for Beginners and Business Professionals
Data Science and Machine Learning Projects in Python: Tabular Data Analytics
Data Science and Machine Learning Projects in R: Tabular Data Analytics
Python Machine Learning & Data Science Recipes: Learn by Coding
R Machine Learning & Data Science Recipes: Learn by Coding
Comparing Different Machine Learning Algorithms in Python for Classification (FREE)
There are 2000+ End-to-End Python & R Notebooks are available to build Professional Portfolio as a Data Scientist and/or Machine Learning Specialist. All Notebooks are only $29.95. We would like to request you to have a look at the website for FREE the end-to-end notebooks, and then decide whether you would like to purchase or not.