Adam Rush

@Adam9Rush

8 March, 2022

Introduction

You’re probably familiar with using closures, and if you’re not, you have probably used a closure without even realising. A closure is a single self-contained block of code that can be executed or passed around your application to be executed. Closures are the same as “blocks” in Objective-C or Lambdas in other languages.

If you have ever used a compactMap or similar, then you’re utilising the power of closures :]

func findUsers(completionHandler: (Bool) -> Void) {
    // Search bank users
    completionHandler(true)
}

You have a straightforward closure defined as a parameter for the callee to detect when execution has finished. This is a widespread use case, and you’ll see the naming “completionHandler” as a very common naming.

You’re not going to explore closures within this article, but you will explore an escaping closure because you must understand this concept.

What is an Escaping Closure?

If you look at the above example, you can call this closure with the following code:

findUsers { success in
    if success {
        print("Success")
    }
}

In your example, you’re calling findUsers and you’ll be returned with a Boolean flag named “success”, which will allow you to detect if the closure was successful or not. In your case, searching users was successful.

However, in your real-world application, you’ll likely return an error or an Array of searched users, perhaps.

var closure: ((Bool) -> Void)?

In your example, you have defined a property that is a closure with the same interface as your function.

func findUsers(completionHandler: (Bool) -> Void) {
    // Search bank users
    closure = completionHandler
}

You can now set your specified property to the value of your completionHandler. This is often important because you want to capture the closure and pass it along in your application code.

However, you’re likely going to get a compiler error right now.

This compiler error tells you that you’re capturing a closure without declaring it in your interface as “escaping”.

An escaping closure means you will be going outside of the closure’s scope when calling. It’s a warning to you as the programmer that it’s not entirely safe, and you’ll likely want to make sure the memory management is handled.

You can do this by using the @escaping syntax.

func findUsers(completionHandler: @escaping (Bool) -> Void) {
    // Search bank users
    closure = completionHandler
}

For sure, it’s safe because we’re not doing anything with this stored closure, but things to look out for retain cycles by retaining objects in memory throughout and failing to deallocate them.


The @escaping functionality has been around since Swift 3


What Next?

You have learnt about using escaping syntax within closures. You have also touched the surface using closures. But do note that closures are vast and cover many different use-cases. Look out for more articles coming soon, digging deeper inside Swift Closures.

Sponsor

Subscribe for curated Swift content for free

- weekly delivered.