Closures with Swift

Doug Galante
8 min readMay 8, 2017

--

Get ready… closures are a difficult topic. Understanding how closures work and why we need them relies heavily on understanding many other concepts in swift. In this post I’ll break down what closures are using some simple examples and hopefully explain just whats going on.

What is a closure?

From the apple documentation:

Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.

Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables. Swift handles all of the memory management of capturing for you.

So what does this mean? To think of it simply — a closure is like a function. It is a piece of code that gets executed when you call it. It can be any number of lines and can have a return if necessary.

The key part about closures is that it can capture values and store references. This allows the closure to be a first-class-object and be passed around in your code. In fact functions are a type of closure — They are a closure that doesn’t capture any values.

Closures can take one of three forms

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.

Functions as a Type

It’s important to remember that functions in swift have type like an Int or a String. The function type is defined by its parameter types and it’s return type. Take a look at the following examples:

func myFunction() {
print("this is my function)
}
// myFunction type: () -> Voidfunc mySecondFunction(x: Int) -> Int {
return x * x
}
// mySecondFunction type: (Int) -> Intfunc myThirdFunction(a: [String], b: [String]) -> Int {
return a.count + b.count
}
// myThirdFunction type: ([String], [String]) -> Int

Because functions have a type and function parameters are a type, you can set a functions parameter as a function type.

func myFunction(otherFunction: (Bool) -> Void) {
otherFunction(true)
}
// myFunction type: ((Bool) -> Void) -> Void

This is how we define the type of a closures.

Capturing Values

Closures can capture values from the surrounding context that they are defined in. Capturing a value basically means that a closure can hold on to a value within the context it was defined even if the original scope in which the closure was defined no longer exists.

I’m going to throw a big chunk of code at you and dissect it to help better illustrate the way closures capture values. In this example we have a class that has a function that returns a closure. We can then call that closure like a function and see how the captured values are represented.

In the example we write out the implementation of MyClass to have one property classString and one function createClosure.

First lets look at the function. It takes in a string and returns a function type.

Within the function we define another variable then nest a function addLetter within the function createClosure. the function addLetter is the same type as the needed return type for createClosure… so we can return it at the end of the function call.

Note that we want to return the function, not the return value of the function. By not writing () after the function we are specifying that we want the function as the return type, not its return value (which is a string).

If we look at the code inside the brackets of addLetter we can see that we use two variables outside its scope — classString and funcString. The addLetter closure captures both of these values when it is created meaning it saves its own reference to those objects (or copies their value if they are not an class).

To demonstrate how the closure is capturing the values or references, lets look at the next few lines of code where we create an optional instance of myClass and call the createClosure function.

  1. We create the instance myClass making it optional so we can remove the instance to nil later and see how it effects the closures.
  2. We create 2 closures closure1 and closure2 by calling the createClosure method on myClass. This sets our closures equal to function types () -> String. The string that these closures return shows the changes that are made to classString and funcString when the closure is executed.
  3. Each time we call closure1 or closure2 it adds a flame or lightning bolt to the classString — but for funcString only a flame or only a lightning bolt is added. Both of these closures reference classString in the same context so they capture and mutate the same value… but since funcString is only in the scope of itself, each function is capturing the value of funcString from a different context.
  4. When we set the myClass variable to nil the closures are still able to work. This should seem strange. Since myClass no longer exists… how can the closure access and mutate the classString property? This is due to capturing the value. The closure holds its own reference to that object or value and can continue to manipulate it even though myClass has left scope.

Since the closure is able to capture and maintain a connection to objects that have been set to nil they have the potential of creating a strong reference cycle. For more info on this topic and how to avoid it check out Strong Reference Cycle Closures here.

Closure Expression Syntax

The final way that a closure can be represented is in a closure expression. The syntax for a closure expression doesn’t require the closure to have a name and can be written directly in with a function call.

First lets look at the basic syntax of a closure expression. I’ll write a simple function that takes a closure as an argument.

myFunction has one parameter— a closure. When we call myFunction it asks us to pass it a function type of () -> Void as an argument. We can do this by creating a function with a name and passing it like so.

This is working as expected. Because the printSomething function is of the type () -> Void we can pass it as an argument to myFunction and the logic inside the closure happens between the two other print statements in myFunction.

We can accomplish the same thing using closure expression syntax like so.

The code inside the brackets is the logic that is executed as the closure. This keeps things clean and simple.

Lets look at another example where the function is a bit more complex.

In this example myFunction has two parameters and returns a string. The string that myFunction returns is dependent on the logic of the closure which returns a string itself.

When calling the function with closure expression syntax we must first pass address the number parameter as normal. The trailing closure syntax then starts by opening a bracket. This time you will notice something different… the word “num” followed by “in”. num is referring to the parameter that we pass the closure (in this case it is 3) and in is signifying that the logic inside the closure is beginning. We can then use num the same way we would use an argument in a function call.

Finally since this closure has a return type of String… we must return a string.

The syntax of closure expressions can look very different depending on the closure and what swift can infer about it — but the same general principals always apply.

Practical Example

A very common use of a closure expression comes in the form of a completion handler. If there is an operation that takes a relatively long time to complete — say a network call or animation — you can use a completion closure to execute some code after that task is complete.

Lets look at simple animation that has two closures as parameters— animation and completion.

withDuration is the time the animation will take, animations is the logic that specifies what views we will be animating and how, and completion is any logic that can be called once the animation is complete.

Notice that animations is of type () -> Void so it can be written with just two curly brackets { }.

The completion handler takes a bool. This means we will need to set up a parameter name for the bool and use in to signify that the logic for the closure is starting { success in logic…. }

I know its pretty confusing and hard to take in. Hopefully seeing some of these examples has helped you understand closures a bit more. In my next post I’ll be going over higher-order functions and talking a bit more about how syntax can change with closures.

Thanks for reading!

--

--

Doug Galante

Aspiring Coder with a Fine Arts Degree ~ Making Time for Climbing, Cooking, Video Games, and Sleep.