In this post we are going to learn, difference between escaping closures and non-escaping closures. Closures are self contained block of functionality that can be pass around and used in your code. If you are not familiar with closures in swift, then you can learn from given below link
https://iostutorialjunction.com/2018/04/how-to-write-closures-in-swift-beginner-tutorial.html
Closures types
There are two type of closures
- Escaping closures
- Non-escaping closures
What are Non-Escaping closures?
A closure is non-escaping closure by default in swift. With non-escaping means that a closure will not live or remain in memory once the function that calls this closure finish execution. So closure needs to be executed before its calling function finish execution.
Example of Non-Escaping closure
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. addTwoNumbers() } func addTwoNumbers() { print("Step 1") performSumFor(10, andSecodNumber: 20) { (result) in print("Result == \(result)") } print("Last Step") } func performSumFor(_ num1: Int, andSecodNumber num2:Int, completionHandler: @escaping (_ resilt:Int) -> Void) { print("Step 2") let result = num1 + num2 print("Step 3") completionHandler(result) } }
In above example you can see, we have a function named, performSumFor. This performSumFor function accepts three parameters and one of them is a closure. In our second function, addTwoNumbers, we are calling performSumFor. For generalizing things better, we also listed steps of execution. If you run this example, output will be like as shown below
- Step 1 printed
- Next print Step 2
- Step 3
- Result == 30
- Last Step
Here you can see clearly, that before ‘Last Step‘ gets printed out. Non-escaping closure finished execution and thus de-allocated from memory. In other words it did not escaped the function from which it gets called.
What are Escaping closures?
Escaping closure are exact opposite of non-escaping closures. Therefore, escaping closures will remain in memory after the function from which they gets called finish execution. You have seen escaping closures in case of API calls where code is running asynchronously and execution time is unknown. Let us look at the example for escaping closures. We will use same example as used above but this time we will call closure asynchronously.
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. addTwoNumbers() } func addTwoNumbers() { print("Step 1") performSumFor(10, andSecodNumber: 20) { [weak self] (result) in guard let _ = self else {return} print("Result == \(result)") } print("Last Step") } func performSumFor(_ num1: Int, andSecodNumber num2:Int, completionHandler: @escaping (_ resilt:Int) -> Void) { print("Step 2") let result = num1 + num2 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { print("Step 3") completionHandler(result) } } }
In above code, we only add comletionHandler execution line inside async queue. Output of above code will be
- Step 1
- Step 2
- Last Step
- Step 3
- Result == 30
So here we saw clearly, that escaping closure gets executed or called after the addTwoNumbers functions finished its execution. So this means, escaping closure will remain in memory and therefore we have to add [Weak self] in closure body to avoid retain count.
Where to go from here
In this tutorial, you learned about difference between escaping and non-escaping closures in swift with example of each case.