Closure in Swift: The Painful one

Shubham Bakshi
8 min readMay 1, 2019

--

Many thanks to our Ahmed Sulaiman for this lovely illustration!

Discover the enhanced version of the article, complete with refined syntax highlighting and all the latest updates, now available on my personal blog! Your feedback and engagement are greatly appreciated and help fuel future content:

As per Swift Documentation :

Closures are self-contained blocks of functionality that can be passed around and used in your code

Anyone trying out closures for some time now must have read this quote and be like

At least I was!

To put it in simple words: a closure is a block of code that you can assign to a variable.

let someVariable = 10let someCoolerVariable = {    return 10}()

Both the constants defined above are essentially the same, an Int type. The only difference between the two is that the first one is written as we have been writing all along and the second one is written using a closure.

I know, I know that’s a really messed up way to declare a variable! Let’s move on. I bet you must have seen the declaration below:

func pretendItsACoolName() {      // Some really complex logic here}

Yeah, It’s a function. What’s more, is that it’s actually a closure. You see functions are special kind of closures. In fact, there are three kinds of closures:

  1. Global functions: Closures that have a name and do not capture any values.
  2. Nested functions: Closures that have a name and can capture values from their enclosing function.
  3. Closure expressions: Unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

If you want to know more about Global and Nested functions, check this out.

But the main star of this article is Closure expression a.k.a. closure (duh?). But why is the name Closures and not Nameless Functions?

Well, Closures can capture and store a reference to any constants and variables from the context in which they are defined. This is known as closing over them, hence the name closures.

Let’s get started

Okay enough with the nomenclature, let’s get down to business!

You can define a closure like this :

let myNickname: (String) -> String = { (name: String) in   return "I am Shubham Bakshi a.k.a. \(name)"}myNickname("Boxy") // I am Shubham Bakshi a.k.a. Boxy

That’s a lot of things to digest at once, I’ll try to break it down bit-by-bit.

  • Closure Type (String) -> String : This tells the compiler that we will have a closure which will take a single parameter, String and will return a String as well. The input parameter/s for our closure has to be written inside round-braces () , even if we have just one (like above), otherwise the compiler will go nuts.
  • Closure Expression (name: String) in : As I said above, all the parameters for the closure goes inside round-braces () . (name: String) is our parameter list. The in the keyword is a separation between closure’s parameter list and the closure’s definition/body.
  • Closure Definition/Body: What follows after the in keyword and before the closing } is the body of the closure. Here you can write whatever rocket science logic you need to write.
  • Closure Call myNickname(“Boxy”) : A Closure is always called using the name of the variable that we assigned the closure to, followed by () (In case we don’t have any parameters for our closure). If we have some parameters for our closure, likeString in our case, we need to pass that parameter as we did in our closure call.

Cut the Code!

Now, we have defined our above closure with the most lengthy way we can, wanna see some shorthand and compiler-inference magic?

Let’s first move our closure type into a typealias as it’s really good practice to use typealias in your code as it improves readability and reusability.

typealias closureType = (String) -> String

Next, we will use shorthand properties in our code, $0,$1….. If you have never worked with them, it seems scary at first.

To break it down, all they signify is the number of parameters that will be passed to our closure. In our case, we are just passing a String parameter so we will access that using $0 . If we had 2 input parameters, we would access the first parameter with $0 and the second parameter with $1.

Since we will be using shorthand properties, we don’t need to write(name: String) in, so we can get rid of that!

So our code now will look like this :

typealias closureType = (String) -> Stringlet myNickname: closureType = {     return “I am Shubham Bakshi a.k.a. \($0)”}myNickname(“Boxy”)

We can reduce this code even more by removing the return keyword and bringing the whole closure definition to the same line. That’s compiler-inference magic for you:

typealias closureType = (String) -> Stringlet myNickname: closureType = { “I am Shubham Bakshi a.k.a. \($0)” }myNickname(“Boxy”)

However, the above code will only work (without explicitly writing the return keyword) when we have only a single line inside our closure body. That’s because when we don’t use the return keyword inside the body, and the closure has to return a String value and we just have a single line of code in our body (that too a String), the compiler is smart enough to figure it out that, the particular String (that is in our closure body), is to be returned, so it doesn’t go nuts this time. But when you add one more line to the body of closure, the compiler will jump all over.

Okay, so what if there is no parameter and no return type for the closure as well. Well, in that case, we use () -> () or () -> Void as our closure type. If you look carefully, you have seen () somewhere else in Swift.

Yup, they are tuples. They are used to contain data of dissimilar types.

Void is an alias of an empty tuple (). When a function or closure doesn’t return anything, it’s return type is Void.

BONUS: Just like you cannot mutate the parameters of the function, as they are implicitly declared let, but you can, if you have declared those parameters as inout , same is the case with Closures.

A Sneak!

Now, If you noticed, I did a little trick on you guys. When I started the article with a closure example, I used:

let someCoolerVariable = {   return 10}()

And in the example above, I used:

typealias closureType = (String) -> Stringlet myNickname: closureType = { “I am Shubham Bakshi a.k.a. \($0)” }myNickname(“Boxy”)

Have you noticed it yet? Okay, okay I will tell you. Look at how I called the first closure and how I called the second closure.

The first one (someCoolerVariable) will be called right after I defined it and the second one (myNickname) will be called when I explicitly call it.

Let me take you on a ride:

let aStubbornClosure = {    print(“I will be called no matter what”)}()let aNiceClosure = {    print(“I will be called when i am needed explicitly”)}

When you run this code, the output on the console will be: I will be called no matter what.

Now these, stubborn closures, are really helpful and popular in cases where you are creating your UI Elements programmatically. As the elements will be initialized and ready for use as soon as the closure body is completed.

Plus, the type of both is not the same. aStubbornClosure is of type () while aNiceClosure is of type () -> () . Which means that aStubbornClosure , is not actually a closure, but a definite value! That’s why, when you run it, you’ll get a warning, as the compiler infers its type to be () which, to be honest, is really confusing.

To break it down, consider this final example:

let aCoolVariable = {    return 10}()let aNotSoCoolVariable = {    return 10}

Type of aCoolVariable is Int which is not a closure, whereas the type of aNotSoCoolVariable is () -> Int , which is a closure.

Trailing Closures

A Trailing Closure is a concept which states that if, a function takes the last parameter as a closure, then while calling that function,

  1. We can omit/remove the name of the closure parameter inside the function
  2. We can close the function parameter list with ) and then write our closure body within { } after the closing ) .
func someFunctionThatTakesAClosure(closure: () -> Void) {    // function body goes here}/* Here’s how you call this function without using a trailing closure */someFunctionThatTakesAClosure(closure: {    // closure’s body goes here})/* Here’s how you call this function with a trailing closure instead */someFunctionThatTakesAClosure() {    // trailing closure’s body goes here}

Capture List

How many times have you seen the following code when you’re working with Closures inside View Controllers:

someClosure = { [weak self] in    // Some complex code here}

The thing inside the square-brackets [] are actually the Capture list. If you want to know the basics of capture list, you can check out Capture List — Bob The Developer.

Just like [ weak self ] , we have [ unowned self ] which helps us in preventing memory leaks that occur due to strong reference cycle. Most of the times, whenever we are using self inside the closures, we need a weak or unowned reference to it.

So, what’s the difference between weak and unowned ?

You typically use unowned when the closure and the captured value (self in our case) will always refer to each other, and will always be deallocated at the same time. We can use [unowned self] in a view controller, where the closure will never outlive the view controller.

You typically use weak when the captured value at some point becomes nil. This can happen when the closure outlives the context it was created in, such as a view controller that’s deallocated before a lengthy task is completed. As a result, the captured value is optional.

Escaping closures

Prior to Swift 3.0, the closures were escaping by-default but after 3.0, closures have been made no-escaping by-default. But what exactly is the difference?

Escaping generally means that the closure will escape or outlive the scope of the context it is being called in (say a function) and exist elsewhere. As the execution ends, the scope of the passed closure has an existence in memory, till the closure gets executed.

In case of non-escaping closures, defined by @noescape,

  1. We pass the closure as a function argument
  2. Do some additional work with function
  3. The function runs the closure
  4. The function returns the compiler back

In case of escaping closures, defined by @escaping,

  1. We pass the closure as the function argument
  2. Do some additional work with function
  3. The function returns the compiler back
  4. At some later stage, closure gets executed as and when required

In my opinion, @escaping closures are really useful when dealing with Asynchronous network request, where the response from the server comes after some delay when even the function that called the service has returned.

Use Cases

The most prominent use cases of Closures can be :

  • Completion Handlers
  • Programatically creating UI Elements
  • Higher-Order Functions
  • Syntactic Sugar

Well, that’s it from my side!

You can connect with me on LinkedIn 👱🏻 or can get in touch with me via other channels 📬

--

--