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

During the coding, when 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 in this discussion we are taking 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 and Swift 2 closure parameters was escaping by default, your closure wouldn’t be escape the function’s body, if no you could mark the closure parameters as @nonescaping.

In Swift 3, they made a change: closure parameters are no-escaping by default, if you wanna to escape the closure execution, you have to use @escaping with the closure parameters. Why they made this change?🤔 Let’s discuss this at the end of the discussion 😋.

1. @nonescaping closures:

When you are passing a closure in function’s arguments, using it before the function’s body gets execute and returns the compiler back. When the function ends, the passed closure goes out of scope and have no more existence in memory.

Here is the lifecycle of the @nonescaping closure: 1. Pass the closure in the function argument, during calling the function. 2. Do some additional work in 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]) { (sum) in
print(sum)
//step 4, finishing the execution
}
}
//It will print the sumof all the passed numbers.

Here, we just called the function and passed the closure, function running the closure. So we are not escaping the execution of the closure. After the step 4 closure will goes out from the memory.

2. @escaping closures:

When are passing the closure in function’s arguments, using it after the function’s body gets execute and returns the compiler back. When the function 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 in containing function:

  • Storage: When you need to store the closure in the global variable, property or any other storage that exist in the memory past of the calling function get executed and return the compiler back.
  • Asynchronous Execution: When you are executing the closure asynchronously on despatch queue, the queue will hold the closure in memory for you, can 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.

Here is the lifecycle of the @escaping closure: 1. Pass the closure in the function argument, during calling the function. 2. Do some additional work in function. 3. Function runs 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
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]) { (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]) { (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.

So, here we are with the meaning of the @escaping attribute. So when you need to escaping the execution of the closure you can 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.

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