What is Escaping And Non-Escaping Closure in Swift?

Introduction

 
Closures are a self-contained block of functionality that can be passed around and used in your code. Closure parameters are @nonescaping by default, the closure will also be executed with the function body. If you want to escape closure, you must execution mark it as @escaping.
 
Closure is like a function you can assign to a variable. You can move the variable around in your code, and call the code of the closure at a later point.
 
Example:
  1. let closure = { (name:String) -> String in  
  2.     return "Hello, \(name)!"  
  3. }  
  4. let message = closure("Pravesh")  
  5. print(message)  
In the above example, the constant closure contains a closure. This closure takes one parameter called the name of type String. The closure itself then returns a String.
 

@nonescaping Closure

 
The lifecycle of @nonescaping closure,
  • Pass the closure as a function argument, during the function call.
  • Do some additional work with function.
  • The function runs the closure.
  • The function returns the compiler back.
Example:
  1. func getSumOf(array:[Int], handler: ((Int)->Void)) {  
  2.         var sum: Int = 0  
  3.         for value in array {  
  4.             sum += value  
  5.         }  
  6.             handler(sum)  
  7.     }  
  8.     func doSomething() {  
  9.         self.getSumOf(array: [16,756,442,6,23]) { [weak self](sum) in  
  10.             print(sum)  
  11.             // finishing the execution  
  12.         }  
  13.     }  
  14. //It will print the sum of all the given numbers.  
In the above example, we just called the function with closure that gets executed at the end of the function's body. Therefore, we are not escaping the execution of the closure. After finishing, the execution closure will have no existence in the memory.
 

@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. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the type of the parameter to indicate that the closure is allowed to escape. There are several ways to escape the closure:
  • Storage:
    When you need to preserve the closure in storage that exists in the memory, part of the calling function get executed and returns the compiler back. (Like waiting for the API.)
  • Asynchronous execution:
    When you are executing the closure asynchronously on the dispatch queue, the queue will hold the closure in memory for you to be used in the future. In this case, you have no idea when the closure will be executed.
The lifecycle of the @escaping closure:
  • Pass the closure as a function argument, during the function call.
  • Do some additional work in function.
  • Function execute the closure asynchronously or stored.
  • The function returns the compiler. 
Example 1 - Storage 
  1. var complitionHandler: ((Int)->Void)?  
  2.     func getSumOf(array:[Int], handler: @escaping ((Int)->Void)) {  
  3.        //here I'm taking for loop just for example, in real case it'll be something else like API call  
  4.        var sum: Int = 0  
  5.         for value in array {  
  6.             sum += value  
  7.         }  
  8.         self.complitionHandler = handler  
  9.     }  
  10.       
  11.     func doSomething() {  
  12.         self.getSumOf(array: [16,756,442,6,23]) { [weak self](sum) in  
  13.             print(sum)  
  14.             //finishing the execution  
  15.         }  
  16.     }  
  17. //Here we are storing the closure for future use.  
  18. //It will print the sum of all the passed numbers.  
Example 2 - Asynchronous execution
  1. func getSumOf(array:[Int], handler: @escaping ((Int)->Void)) {    
  2.         var sum: Int = 0    
  3.         for value in array {    
  4.             sum += value    
  5.         }    
  6.         Globals.delay(0.3, closure: {    
  7.             handler(sum)    
  8.         })    
  9.     }    
  10.     func doSomething() {    
  11.         self.getSumOf(array: [16,756,442,6,23]) { [weak self](sum) in    
  12.             print(sum)    
  13.             // finishing the execution    
  14.         }    
  15.     }    
  16. //Here we are calling the closure with the delay of 0.3 seconds    
  17. //It will print the sum of all the passed numbers.   
Escaping closures are often associated with asynchronous control flow, like in the following,
  • A function starts a background task and returns immediately, reporting the result of the background task via a completion handler.
  • A view class stores a closure in a property as an event handler for a button pressed event. The class calls the closure every time the user presses the button. The closure escapes the property setter.
  • You schedule a task for asynchronous execution on a dispatch queue using DispatchQueue.async. 

Why they made by default @nonescaping closure

 
There are many different benefits of making non-escape the default. The most important benefits are performance and code optimization by the compiler because if the compiler knows that the closure is non-escaping, it will take care of the memory allocation for the closure.
 
Another reason is that we can use this method ourselves without problems in non-escaping closures because the closure executes before the function returns. This way, the self will be there for sure. We don't need to use the weak self, as this is an additional feature.


Similar Articles