Understanding Escaping Closures in Swift
12 Sep 20171. Concept of Escaping Closures
This article assumes a basic understanding of closures. If you are not familiar with closures, please read the Swift Closure article first before continuing.
When a closure is said to “escape” a function, it means that the closure is passed as an argument to the function but is executed after the function has returned. This concept of closures escaping the scope of a function challenges the traditional understanding of variable scope. It allows a closure to persist beyond the lifetime of the enclosing function, which is different from the usual scope rules for local variables. In other words, escaping closures can be executed outside the function that originally defined them.
While the idea of a local variable (typically values like Int
, String
, etc.) surviving outside a function might seem similar to using global variables within a function, escaping closures offer more control over the execution order of functions.
Escaping closures are useful for defining the execution order between functions, even allowing one function to run only after another has completed.
Ensuring the order of execution of functions is crucial, especially when dealing with asynchronous operations. Consider an app that retrieves JSON data from a server to display it on the screen. In this scenario, a networking library like Alamofire
is often used in the following manner:
The Alamofire.request(urlRequest)
method sends a request to the server, typically to retrieve JSON data using the GET method. The result is obtained through a Response
object. Usually, functions that send requests to a server and receive responses work asynchronously, returning immediately after sending the request. How is it possible to ensure that the response is received and processed in a way that guarantees proper sequencing? The answer lies in the concept of escaping closures. The completionHandler
parameter in the responseJSON
method is implemented as an escaping closure, indicated by the { response in }
part.
Now, let’s explore some code examples to understand how escaping closures work.
2. Storing Closures Outside Functions
In this example, the MyClass
function callFunc()
calls two functions, withEscaping(completion:)
and withoutEscaping(completion:)
. The withEscaping(completion:)
function takes a closure parameter marked as an escaping closure using the @escaping
keyword. In this function, we store the closure in the completionHandlers
array outside the function’s scope. This means that the closure escapes the function and can be executed at a later time.
3. Async Inside Async
As mentioned earlier, escaping closures are commonly used in asynchronous operations, especially in networking code with completionHandlers
. To demonstrate this, let’s consider a scenario where you need to retrieve data from a server using a Server
class and update the UI once the data is received. To manage this, you might want to create a class with static methods for handling server requests.
Here’s the sequence of how the code works:
- In
ViewController
, you call theServer
class’sgetPerson(completion:)
function to request the necessary data. - Inside the
getPerson(completion:)
function,Alamofire
sends a request to the server, and the{ response in }
part ofresponseJSON
is executed only after the request has completed. This part uses an escaping closure. - The
completion
closure, which is also an escaping closure, is called in order to send the data (persons) back to the original ViewController. It’s important to perform UI updates on the main thread, so we useDispatchQueue.main.async
to ensure this. - Finally, the
completion
closure inViewController
is executed. Here, you can check if the data retrieval was successful and update the UI accordingly.
References
- Apple Inc. The Swift Programming Language (Swift 3.1) - Escaping Closure
- escaping closure swift3
- [What do
mean @escaping and @nonescaping closures in Swift?](https://medium.com/@kumarpramod017/what-do-mean-escaping-and-nonescaping-closures-in-swift-d404d721f39d)