“@escaping” and “non-escaping” in Swift

Moussa Hellal
3 min readJun 4, 2023

In this article we are going to talk about @escaping and non-escaping in Swift, understand the main differences, and check the sample code for that.

“@escaping” and “non-escaping” are terms used to describe closures in Swift.

In case you don’t know what is a closure:

A closure in Swift in simple words is a block of code that we can pass as a parameter to a function, or assign to a variable.

Escaping

“escaping closure” is a closure that outlives whatever the function that it’s defined in. In other words, we use @escaping for a closure that will be executed later on. Most famous usage of @escaping is calling a network API which can outlive the function itself and take sometime to be finished.

An example of this would be helpful to grasp this theory:

You can create a new playground and copy this code:

func performAsyncTask(completion: @escaping () -> Void) {
DispatchQueue.global().async {
// Simulating an asynchronous task
Thread.sleep(forTimeInterval: 2.0)
completion() // Calling the completion closure after the task is finished
}
}

In this example we have a function named performAsyncTask which will simulate an asynchronous task that will take 2 seconds.

As you see here we have our escaping closure defined as a parameter that will be triggered after our async task has completed.

Now the action and testing this with


import Foundation

// Escaping closure example
func performAsyncTask(completion: @escaping () -> Void) {
DispatchQueue.global().async {
// Simulating an asynchronous task
Thread.sleep(forTimeInterval: 2.0)
completion() // Calling the completion closure after the task is finished
}
}


// Testing the escaping closure
print("Before async task")
performAsyncTask {
print("Async task completed")
}
print("After async task")

As you can see here we have only added the print() and calling our function and passing (print(“Async task completed”)) as our escaping closure.

If you run this code you will notice something :

Before Async task => is Printed correctly

After Async task => is printed correctly but as you can see it’s executed before our escaping closure.

Async task completed => printed out after 2 seconds. That means our closure was stored and fired at a later stage.

Perfect! I hope you got what is @escaping by now and what is does, you can play out with this function and add some seconds, execute some extra code and see for yourself.

Non-escaping

“non-escaping closure” is a closure that must be executed before the function returns. By default any passed closure in non-escaping. Hence, this code can explain it.

Copy and paste into your playground and run:

// Non-escaping closure example
func performSyncTask(completion: () -> Void) {
// Performing a synchronous task
print("Performing a synchronous task")
completion() // Calling the completion closure immediately
}


// Testing the non-escaping closure
print("Before sync task")
performSyncTask {
print("Sync task completed")
}
print("After sync task")

If you run this code you will notice something :

Our code is executed in the order that we have implemented and voila this is non-escaping.

I appreciate you choosing to spend some of your day with me. I hope that my piece was informative and helpful to you.

Farewell, keep growing and learning. See you in the next one. ✌️

Make sure to follow me on Twitter to keep receiving the newest articles:

https://twitter.com/codeWithMoses

--

--