Completion Handler in Swift with @escaping and @nonescaping closures.

Dhaval Kansara
4 min readMar 16, 2020

--

Swift Language Guide Document

Completion Handlers is not an easy concept if you are not good with closures. If you are not comfortable with them, you can learn it from Swift Closures.

Closures are incredibly powerful tools, but if you can’t put them to use, they won’t do you much good.

A common application of a closure is the completion handler. It works roughly like this:

  • You’re executing a lengthy task in your code, like downloading a file, making a calculation, or waiting for a webservice request
  • You want to execute some code when the lengthy task is completed, but you don’t want to “poll” the task continuously to check if it’s finished
  • Instead, you provide closure to the lengthy task, which it will call when the task is completed

Introducing Completion Handlers:

Before we design one for ourselves, let’s take a look at the time you saw one previously. When you move to the next view controller, you might have seen something like this.

import UIKitlet firstVC = UIViewController()
let nextVC = UIViewController()
firstVC.present(nextVC, animated: true, completion: nil)
  • The completion parameter ask you to enter a closure block whose type is () -> () or () -> Void. So, let’s enter a closure block.
firstVC.present(nextVC, animated: true, completion: { () in print("Done🔨") })      // Done🔨
  • “Done”, will be printed only after firstVC has moved to secondVC

Design Completion Handler

It’s time to design a function like present above. You are now constructing a block which will print a total of first thousand number.

Design Stuff Block

First, let’s create a closure block whose type is (Int) -> (). When you pass Int as total, it will print a total.

let block: (Int) -> Void = { total in
print(“Sum of the first 1000 number is \(total)”)
}

Design Function Block

Now, let’s create a function that will do a summation of the first thousand numbers. Once summation is done, you are going to call, block(total) to identify that you are done with a summation of the first thousand numbers.

func sumOfFirstThousandNumber(completionHandler: (Int) -> Void) {var total = 0for i in 1…1000 {
total = total + i
}
completionHandler(total)
}
  • When you call sumOfFirstThousandNumber, It will print “Sum of the first 1000 number is 500500”.
sumOfFirstThousandNumber(completionHandler: block) 
// Sum of first 1000 number is 500500

From Swift 3.x, closure parameters are @nonescaping by default, It means closure will also be executed with the function body if you wanna escape closure execution mark it as @escaping.

1. @noneescaping closures:

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

Example:

func sortArray(array:[Int], handler: (([Int])->Void)) {   // step 2
var sortedArray: [Int] = []
sortedArray = array.sorted();
// step 3
handler(sortedArray)
}func doSomething() { // setp 1
sortArray(array: [50,333,434,2,8,3,54,73,99,83,13]) {(result) in
// step 4
print("Sorted Array: \(result)")
}
}doSomething() // Sorted Array: [2, 3, 8, 13, 50, 54, 73, 83, 99, 333, 434]

2. @escaping closures:

Suppose in the above scenario if we need those sorted numbers after the function return, then you have to mark it as @escaping closure else you will receive the following error.

var findMaxFromArray: (([Int])-> Void)?func findMaxNumber(array:[Int], handler: @escaping ([Int])->Void) {   //step 2
handler(array)
//setp 3
findMaxFromArray = handler
}func doSomething() { //setp 1
findMaxNumber(array: [11,52,33,34,5,65,7,8,29,10]) {(result) in
let maxNumber = result.max()! //step 4
print(“Max number from Array: \(maxNumber)”)
}}doSomething()//setp 5
findMaxFromArray!([100,300,754,222,44,432,535])
Output: Max number from Array: 65
Max number from Array: 754

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

That’s all for this particular post. I hope I was able to explain how to design and use the completion handler.

Feel Free to post your comments if you face any issues. You can 👏 if you liked the article. Do you know that you can 👏 50 times in a single post? try it.

Thanks for reading…!!!

Dhaval Kansara
iOS | Flutter

--

--