Swift Closures: In this tutorial, you’ll learn what is a closure, syntax, types of closures in Swift with examples.
In the tutorial Swift functions, we created a function using func keyword. Nonetheless, there is another special type of functions in Swift, known as terminations that can be defined without using watchword func and a function name.
Like functions, terminations can acknowledge parameters and return values. It additionally contains a set of statements which executes after you call it and can be appointed to a variable/constant as functions.
Swift Closures are different sorts of Swift functions which can be defined without using catchphrase func and a function name.
Like Swift functions, swift closures likewise can acknowledge parameters and return values. It likewise contains a set of statements which executes after you call it and can be assigned to a variable/consistent as functions.
Closures are primarily used for two reasons:
In this article, you will learn-
- 1 1. Completion blocks
- 2 Syntax of closure
- 3 Example 1: Simple Closure
- 4 Example 2: Closure that contains statements
- 5 Example 3: Closure that accepts parameter
- 6 Example 4: Closure that returns value
- 7 Example 4: Passing Closures as a function parameter
- 8 Trailing Closure
- 9 AutoClosure
- 10 Example 7: Autoclosure
- 11 Autoclosure with arguments and return value
- 12 Escaping vs No Escaping Closures
- 13 Escaping Closure
- 14 Closure as a completion handler
- 15 How completion handler works?
- 16 Example 11: Closure as a completion handler
1. Completion blocks
Closures assist you with being informed when some task has completed its execution.
2. Higher order functions
Closures can be passed as an input parameters for higher order functions. A higher order work is only a type of function that acknowledges work as an input and returns worth of type function as output.
For this intention it’s smarter to use closures in replacement of function since closures overlooks the func catchphrase and function name that makes the code more readable and short.
Syntax of closure
Closure expression syntax has the accompanying general structure:
{ (parameters) -> return type in statements }
Notice the use of in watchword after the return type. The in watchword is used to separate the return Type and statements inside the closure. The closure acknowledges 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 straightforward closure{ } that takes no parameters, contains no statements and doesn’t return a worth. This closure is appointed to the constant simpleClosure.
We call the closure as simpleClosure(), however since it doesn’t contain any statements, the program does nothing.
Example 2: Closure that contains statements
let simpleClosure = { print("Hello, World!") } simpleClosure()
At the point 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 acknowledge parameter and doesn’t return a worth.
On the off chance that you need to unequivocally defined the sort of the closure, you can do as such as let simpleClosure:() – > ().
Unlike the primary 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")
At the point 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 doesn’t return value. You can use the worth passed inside the statements of the closure by putting a parameter name followed by in watchword.
Recall the use of in catchphrase is to separate the parameter name with the statements. Since the closure acknowledges a String, you need to pass the string while you call the closure as simpleClosure(“Hello, World”). This executes statements inside the closure and outputs Hello, World! in the console.
Example 4: Closure that returns value
A closure can likewise return value, as functions. On the off chance that you need to return value from closure, you should explicitly add the sort 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)
At the point 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) since Swift can’t consequently infer the closure that returns a value. The sort (String) – > (String) states that the closure takes an input of type String and furthermore returns a value of type String.
The closure additionally returns a value using the return catchphrase 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 likewise pass closure as a parameter to a function as:
func someSimpleFunction(someClosure:()->()) { print("Function Called") } someSimpleFunction(someClosure: { print("Hello World! from closure") })
At the point when you run the above program, the output will be:
Function Called
In the above program, the function acknowledges a closure of type ()- >() i.e takes no input and doesn’t return any value.
Presently when calling the function someSimpleFunction(), you can pass the closure { print(“Hello World! from closure”) } as a parameter.
The function consider triggers the print(“Function Called”) statements inside the function which outputs Function Called in the screen. Notwithstanding, the closure statement isn’t executed because you have not settled on the decision to the conclusion.
You can call the closure just as someClosure() which executes the statement inside the closure.
func someSimpleFunction(someClosure:()->()) { print("Function Called") someClosure() } someSimpleFunction(someClosure: { print("Hello World! from closure") })
At the point when you run the above program, the output will be:
Function Called Hello World! from closure
Trailing Closure
On the off chance that a function acknowledges a closure as its last parameter, the closure can be passed like 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") }
At the point when you run the above program, the output will be:
Hello Swift Community! Hello World! from closure
In the above program, function someSimpleFunction() acknowledges a closure as a last parameter. Along these lines, while calling the function, rather than 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”) } resembles the body of a function rather than function argumnt, however recall it’s still an argument to the function.
Because of trailing closure, we haven’t determined the boundary name for the closure which makes the code more limited and more readable.
It isn’t mandatory to write trailing closure. Nonetheless, it is suggested for readability reason when a function acknowledges a closure as a last argument.
AutoClosure
A closure which is marked with @autoclosure watchword is known as autoclosure. @autoclosure catchphrase creates an automatic closure around the expression by adding a {}. Consequently, you can discard braces {} when passing closures to a function.
The fundamental benefit of using autoclosure is that you don’t have to enclose 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!")
At the point 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 acknowledges 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!")
At the point 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. Along these lines, you don’t need 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. Be that as it may, even if you pass the arguments, they get overlooked and can’t be used inside the closure. This is on the grounds that you can’t define the parameter to use it as { arg in }.
In this manner, it is recommended to create autoclosures that don’t take arguments but can return value. Value is the expression that is wrapped within 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")
At the point 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 additionally the return value of the closure.
In this way, 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")
At the point 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 furthermore 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 through autoclosure is called as someClosure(“Hello World”), it can’t acknowledge any parameters, it actually returns and prints Good Morning.
Escaping vs No Escaping Closures
No Escaping Closure
A closure is supposed to be no escaping when the closure is passed as an argument to the function, and is called before the function returns. The closure isn’t used outside of the function.
In Swift, all closure parameters are no escaping by default. The idea 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") }
At the point when you run the above program, the output will be:
function called closure called
In the above example, the closure is supposed to be no escaping on the grounds that the closure myClosure() is called before the function returns and closure isn’t used external 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, however 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") }
At the point when you run the above program, the output will be:
function called closure called
In the above example, we have proclaimed a variable closureArr that can storeanarray of closures of type ()- >().
Presently, on the off chance that we append the closure myClosure defined inside the scope of the function to the closureArr defined outside of the function, the closure myClosure needs to escape the body of the function.
In this way, the closure should get away and marked with @escaping watchword.
Example 12: No escaping closure
In the above No Escaping Closure area, we depicted a closure should 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 notice since statements showing up after the return statement(in our case myClosure()) doesn’t execute on the grounds that the return statement moves the control of the program to the function caller.
In this way, how would we test with the goal that the closure is called after the function returns. It can be done if the closure call is placed inside an asynchronous activity.
Coordinated activity waits for the activity will complete/finish prior to moving to the next statement (top to bottom order). Furthermore, Asynchronous moves to the next statement even of whether the current activity hasn’t finished.
Accordingly, statements that is put inside an asynchronous operation may execute later eventually.
func testFunctionWithNoEscapingClosure(myClosure:@escaping () -> Void) { DispatchQueue.main.async { myClosure() } return }
In the above program, DispatchQueue.main.async runs the block of code asynchronously. In this way, presently. the closure call myClosure() may happen even after the function returns. Thus, the closure needs to be escaping and is marked with @escaping catchphrase.
Closure as a completion handler
Completion handler are callbacks/notices that allows you to play out some activity when a function finishes its task.
completion controller are generally used in asynchronous activities with the goal that the caller can know when the activity has finished to play out some activity after the completion of the activity.
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")
At the point 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 likewise 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 function
- print(“function called”) outputs function called in the console.
- You may play out some work inside the function. Until further notice just a print(“some work here”) statement that outputs some work here in the console.
- A basic call to the closure as completion () will send the callback and moves the control of the program to the statements inside the closure.
In this way, print(“call back received”) executes which outputs call back received in the console.
- After that the program control again gets back to the conclusion call, and executes articulation print(“after calling callback”) which yields in the wake of calling callback in the support.
- After the statements inside the function executes, program moves the control to the function call doSomeWork()and at that point executes the next statement print(“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) }
At the point when you run the above program, the output will be:
Code, Take a Nap and Relax
In the above program, we have declared a variable closeButtonPressed that derides if user has tapped close catch on playground. Think on the off chance that you press the nearby catch, variable closeButtonPressed will be true.
The function codeinPlayground acknowledges a closure as an argument. The closure completion acknowledges a String however doesn’t return a value. Since the closeButtonPressed is assigned false, statement inside if statement doesn’t execute and closure isn’t called.
Presently, on the off chance that you assign the closeButtonPressed to true (i.e., when user passed close catch) as var closeButtonPressed = true, statements inside if executes and closure is called.
At the point 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 since when user taps the nearby catch, we would prefer not to execute statements inside the function codeinPlayground, rather complete its execution by calling the closure completion(“Close the playground”).
This way we get an opportunity to deal with every one of the last occasions identified with the function inside the statements of the closure. For our situation we have output the message in console as print(msg).
Thanks for reading! We hope you found this tutorial helpful and we would love to hear your feedback in the Comments section below. And show us what you’ve learned by sharing your photos and creative projects with us.