What do mean @escaping and @nonescaping closures in Swift?
What do mean @escaping and @nonescaping closures in Swift?

What do mean @escaping and @nonescaping closures in Swift?

Pramod Kumar
AppleCommunity
Published in
4 min readMay 16, 2017

--

During the code, whenever you are working with the functions, may have run with the @escaping or @nonescaping attributes. Have you ever given time to think šŸ¤” about, what it means? So here, we are going to discuss about these terms.

What are closures?

Closures are self-contained blocks of functionality that can be passed around and used in your code.

In Swift 1.x and Swift 2.x, closure parameter was @escaping by default, means that closure can be escape during the function body execution. if donā€™t want to escape closure parameters mark it as @nonescaping.

In Swift 3.x, Apple made a change: closure parameters became @nonescaping by default, closure will also be execute with the function body, if wanna escape closure execution mark it as @escaping. Why Apple made this change?šŸ¤” Letā€™s discuss this at the end of the discussion šŸ˜‹.

1. @nonescaping closures:

When passing a closure as the function argument, the closure gets execute with the functionā€™s body and returns the compiler back. As the execution ends, the passed closure goes out of scope and have no more existence in memory.

Lifecycle of the @nonescaping closure:
1. Pass the closure as function argument, during the function call.
2. Do some additional work with function.
3. Function runs the closure.
4. Function returns the compiler back.

Example:

func getSumOf(array:[Int], handler: ((Int)->Void)) {
//step 2
var sum: Int = 0
for value in array {
sum += value
}

//step 3
handler(sum)
}

func doSomething() {
//setp 1
self.getSumOf(array: [16,756,442,6,23]) { [weak self](sum) in
print(sum)
//step 4, finishing the execution
}
}
//It will print the sumof all the given numbers.

Here, we just called the function with a closure, that gets executed at the end of the functionā€™s body.
So we are not escaping the execution of the closure. As the step 4 get executed closure will have no existence in the memory.

2. @escaping closures:

When passing a closure as the function argument, the closure is being preserve to be execute later and functionā€™s body gets executed, returns the compiler back. As the execution ends, the scope of the passed closure exist and have existence in memory, till the closure gets executed.
There are several ways to escaping the closure:

  • Storage: When you need to preserve the closure in storage that exist in the memory, past of the calling function get executed and return the compiler back. (Like waiting for the API response)
  • Asynchronous Execution: When you are executing the closure asynchronously on dispatch queue, the queue will hold the closure in memory for you, to be used in future. In this case you have no idea when the closure will get executed.

When you will try to use the closure with these option the swift compiler will show the error.

Lifecycle of the @escaping closure:
1. Pass the closure as function argument, during the function call.
2. Do some additional work in function.
3. Function execute the closure asynchronously or stored.
4. Function returns the compiler back.

Example 1 (Storage) :

var complitionHandler: ((Int)->Void)?    func getSumOf(array:[Int], handler: @escaping ((Int)->Void)) {
//step 2
//here I'm taking for loop just for example, in real case it'll be something else like API call
var sum: Int = 0
for value in array {
sum += value
}
//step 3
self.complitionHandler = handler
}

func doSomething() {
//setp 1
self.getSumOf(array: [16,756,442,6,23]) { [weak self](sum) in
print(sum)
//step 4, finishing the execution
}
}
//Here we are storing the closure for future use.
//It will print the sumof all the passed numbers.

Example 2 (Asynchronous Execution) :

func getSumOf(array:[Int], handler: @escaping ((Int)->Void)) {
//step 2
var sum: Int = 0
for value in array {
sum += value
}
//step 3
Globals.delay(0.3, closure: {
handler(sum)
})
}

func doSomething() {
//setp 1
self.getSumOf(array: [16,756,442,6,23]) { [weak self](sum) in
print(sum)
//step 4, finishing the execution
}
}
//Here we are calling the closure with the delay of 0.3 seconds
//It will print the sumof all the passed numbers.

Here we are with the meaning of the @escaping attribute. So, when you need to escape the execution of the closure use @escaping attribute in Swift 3. The above shown error of compiler will disappear after making closure as escaping by using the @escaping attribute.

Why they made @nonescaping by default?

There are many different benefits of making non-escaping as by default. The most important benefits are performance and code optimisation by the compiler, because if the compiler knows that the closure is non-escaping, will take care about the memory allocation for the closure.

And another one is, we can use self without problems in non-escaping closures because the closure executes before the function returns so the self will be there by sure. We donā€™t need to use weak self this is the additional feature of it šŸ˜‰.

In Swift 3, closures are non-escaping by default, can be use @escaping if not what we want. Non-escaping closure defiantly will execute before the function returns.

šŸ“£ Always remember to use weak self while using a closure. āš ļø

Thank you for reading, please hit the recommend icon if like this collection šŸ˜Š . Questions? Leave them in the comment.

--

--