Swift Closures — Everyday Gems Part 2 of 2

Keith Elliott (keithelliott.co)
Swift Programming
Published in
9 min readFeb 26, 2016

--

It’s time for the mind blowing stuff! If you didn’t read part 1, do that first. We are going to kick it up a notch with this article.

Swift is a powerful language; it’s really hard to cover all the good parts in a few articles. I’ll try to give a jump start with the areas that I find particularly useful. Today we are going to cover Capturing Values, Nonescaping Closures, and Autoclosures. Let’s rock!

Capturing Values

One of the huge benefits of using closures is their ability to maintain access (read and write) to constants and variables written inside the closure body.

A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.

The Swift Programming Language (Swift 2.1): Closures

Let’s break this thought down into an example we can work with. Do you remember seeing Superman III? In one of the subplots, Gus Gorman develops a way to embezzle money from his employer using a technique called salami shaving or penny shaving. Salami shaving basically means that we can perform a series of small transactions that viewed in their entirety could have a big effect. In Superman III, Gus rounded transactions and moved a penny into his own account in each transaction. Let’s examine the code below to show how this could be done with a closure running in a playground!

I’ve created a struct called PennyShaver for our purposes of “shaving money.” I added two static variables and one instance variable that we will access from our closures — our captured values! The createPaymentCalculator is a creation method to either create a calculator that handles overtime or one that ignores overtime pay. Either way, our goal is to count the number of people that we shave and to keep a running total of the amount of money we have taken after calculating payroll amounts.

Our creation method createPaymentCalculator returns a nested function, which if you remember from part 1, is a type of closure. Because we are returning a closure, we have access to values that are within the scope of our closure, meaning we can see arguments passed to the outer creation function and variables defined within the struct PennyShaver. In our case, we are going to calculate the payment owed and then subtract the amountToSteal from it.

In our example above, we create a PennyShaver struct, passing in an amountToSteal value of $0.10. Each time we calculate payments, we will steal that amount and keep a running tally of the totals and number of people affected.

To see just how effective this could be, I created a large payroll with which to test our code. I used 50 people and varied the number of hours and hourly pay rates for each worker. In the case below, I was able to shave $5.20 from the overall payroll, affecting 52 people.

Did I mention that playgrounds are awesome?! If you missed my post on Playgrounds, you should read it to see what all the fuss is about.

Nonescaping Closures

To explain a nonescaping closure, we first have to understand how an escaping closure works. An escaping closure is defined when you pass a closure as an argument to a function and it is allowed to “escape” and outlive the scope of the function. What that means is that I can create a closure, assign it to a variable, pass the variable to a function that accepts a closure, and then use my variable to continue to execute the closure after the function has returned.

The implication is that we can’t fully benefit from Swift compiler optimizations on any functions that take closures as arguments because the compiler can’t determine if we will need the closures outside of the function. Hence, the Swift team added the noescape attribute to give the Swift compiler the “go-ahead permission” to perform additional optimizations because we are stating that we don’t need the closure past the life of the function.

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @noescape before the parameter name to indicate that the closure is not allowed to escape.

The Swift Programming Language (Swift 2.1): Closures

First, let’s look at an example that allows escaping closures. My updateServerCall function takes a closure as an argument. Nothing special here. The fact that we don’t provide the noescape attribute means that the closure could be used in multiple places once this function returns. In our case, we simply call the function using a closure expression.

Let’s re-write this example to store a reference to the passed in closure. The example below shows a simple notifier by storing callbacks that we can use later to signal an event has occurred. Our registerListenerCallbacks function again takes a closure as an argument. But notice — this time we add the passed in closure argument to our predefined array callbackListenerList for later use.

We can exercise our function with a loop that calls our registerListenerCallbacks function with new created closure expressions. Our closure expressions are really simple, as they just print the message string passed as an argument. Pay particular attention to the fact that just because we have added the closures to a list they aren’t executed immediately. We still have to grab a closure from our list before we can execute it. In our example, I pull the first closure in the list and call it passing true and a short string message.

What happens if we try to convert our registerListenerCallbacks function into one that expects a nonescaping closure? Let’s see. In the example below, I have created the same register function above, only adding the nonescape attribute to the closure argument. As you can see, Xcode complains and lets me know that the closure I am attempting to add to the callback list isn’t possible. With the nonescape attribute, you signal to Xcode that you are positive the closure isn’t needed once the function returns. The Swift compiler is free to do it’s magic and optimize away. However, if Xcode were to allow you to add the closure to the list, the compiler couldn’t optimize the function. The Swift compiler would have no clue where and if you would use the closure in the future.

Sure, this seems like a small improvement, but it could have a larger effect in the speed of our code since each optimization can add up. Swift is fast, and you can tweak the compiler settings in Xcode to make it run even faster out of the box. Watch the Optimizing Swift Performance (WWDC 2015) video to gain additional insights. Imagine running low level graphics routines that stress the iPhone to its limits, where memory and speed count. Under that type of scenario, having additional tools in your tool belt will come in handy.

Autoclosures

Saving the most difficult concept to grasp for last, it’s time to tackle autoclosures. Chances are high that ou have already used them without knowing it. Chances are even higher that you probably won’t have a frequent need to create one on your own. However, I’m a firm believer that you should understand, at some level, how your code works.

An autoclosure is a way for you to pass an expression to a function as an argument and have the function treat it as a closure so that you can control when the expression executes. For example, you might have code that you want executed inside a function only once a condition is met. Further imagine that the expression you want to delay execution is time and resource intensive. In a situation like that, being able to delay or prevent the expression from running would be helpful.

An autoclosure is a closure that is automatically created to wrap an expression that’s being passed as an argument to a function.

The Swift Programming Language (Swift 2.1): Closures

Let’s work through an example to see this in action. In the following example, I create a createFormattedGreeting() that takes closure as an argument. This function uses the return value of the closure to print out a formatted name and return the string. When I want to execute the function, I first create a variable formattedPerson to hold a closure expression and code it to return a tuple with the value (“Jack”, “Bauer”). Next, I can execute the createFormattedGreeting by wrapping my formattedPerson() call with {} to create a closure expression as my function argument.

The above format works, but it seems odd that we have to wrap our closure expression formattedPerson in {} to create another closure around it. Looking at the version below, we can fix this by including the autoclosure attribute. It’s really nothing more than syntactic sugar, but it does make our code a little cleaner.

Overusing autoclosures can make your code hard to understand. The context and function name should make it clear that evaluation is being deferred.

The Swift Programming Language (Swift 2.1): Closures

The only real potential issue with the code in the previous example has to do with the nonescaping closures. Using the autoclosure attribute also implies the noescape attribute, meaning that we can’t use escaping closures with this syntax. If you want to use autoclosures and still allow your closures to escape, you need to modify your function signature to include escaping as I have done below.

Honestly, autoclosures are interesting but may not prove useful in your everyday coding challenges. For the most part, the elegance you get with the shorter syntax needs to be carefully weighed against code readability for other developers on your project.

Final Thoughts

Swift closures are a key feature of the language. We covered some of the more obscure elements of closures today. Hopefully, it is clearer now how valuable capturing values could be in your everyday tasks. And while noescaping and autoclosure attributes may not be useful all the time, having some awareness of their use could prove beneficial for a future coding task. As I mentioned in my last article, the only way to get comfortable with closures is to put them to use in your code. Why not fire up Xcode, create a playground and experiment! You can get the playground that I used in our examples here.

If you’re interested in general thoughts on programming, why not check out my other post on why I code.

If you find this post helpful, please recommend it for others to read. You can visit me at www.gittielabs.com and subscribe to my RSS feed so that you won’t miss a post. I’m also putting together a video course to teach Swift development and could use your input on topics you feel would be helpful. Thanks for reading!

--

--

Keith Elliott (keithelliott.co)
Swift Programming

Tech vet, 20+ yrs from dev to CTO, startup enthusiast, husband, father of 5 + foster child. Eager to empower startups and motivate devs, thriving amid chaos.