Finding Closure: Using closures in Swift

10 minutes to read

You may already be familiar with closures. They’re fairly common in most programming and scripting languages, such as Ruby and Javascript (they’re used extensively in JQuery), though some languages have introduced them only recently (such as PHP). Coming from PHP, however, closures have been the hardest thing for me to understand - PHP doesn’t have them. If you have a strong background in Javascript, it’s likely that you already know how to use closures. They’re used frequently within Javascript frameworks like JQuery. A common example of a closure in Javascript is the setTimeOut function.

What they are

As JQuery’s introduction to closures notes, it’s not a simple task to describe closures in a sentence or two (though they certainly try). In short, closures in Javascript are a way of having extremely local functions within the scope of a single variable or another function. Another way of saying this is that closures are functions that can be stored inside a variable. In fact, they are functions that are bound to that variable.

Alan Skorkin had the simplest explanation of closures for me, using Ruby:

A closure is basically a function/method that has the following two properties:

  • You can pass it around like an object (to be called later)
  • It remembers the values of all the variables that were in scope when the function was created. It is then able to access those variables when it is called even though they may no longer be in scope.

Let’s quickly review what functions are. I discussed these in The Basics:

Functions are mini-programs that live within your application to perform very specific tasks. For example, in your email client, a function exists that connects to your mail server and asks if there are any new messages.

Where functions have very strict variable scope – they can only access variables passed to them as parameters, or local variables set inside the function – closures have a wider scope of variable use. Closures are not restricted to the variable data passed to them through parameters or set within the function itself. Closures have access to the variables they are assigned to.

 

Let’s look at an example in Javascript (from W3Schools):

 

[swift] var add = (function () { var counter = 0; return function () {return counter += 1;} })(); [/swift]

This closure shows both the basic construction of a closure in Javascript, but also how a closure can be created as a nested function. The closure sets an initial value of 0 to the counter variable, and increments it every time the add closure is called.

Variable scope in closures

Closures seem to act similarly to an object. The functionality described in a closure is attached to the variable it is a part of, and can be run whenever that variable is accessed later. As Mozilla’s developer documentation suggests, closures are a kind of object, in that “they allow us to associate some data (the object’s properties) with one or more methods.”

The difference between closures, objects, and functions, however, is that closures turn variable scope on its ear. Variable scope refers to how and where a variable is accessible within your application. Variables defined inside a function are only accessible inside that specific function. Variables defined outside of that function are likewise not accessible from inside the function.

Objects muddy this a bit, in that variables defined inside an object class are accessible to functions defined within that object class. However, variables defined inside of one object class are generally not available inside another object class (unless that class extends or is a child of the other class). Likewise, variables defined outside of an object class are generally not available inside that object class.

This can be a bit confusing, so here are some examples in Swift.

According to The Swift Programming Language, 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, hence the name “closures”.”

In other words, closures can access the contents of the variables that define them. This turns variable scope on its ear, as now the inline function defined by the closure has access to variable data outside of its scope.

Using closures

Syntax

{ (parameters) -> return type in
        statements
}

 

Closures seem to be used most in two contexts:

  • Function parameters, and
  • Nested functions

 

Using closures in function parameters

In Swift, you can supply a closure in place of a variable or constant when calling a function. In the example below, instead of passing a variable to the .map() function, then running through a bunch of logic to parse the contents of that variable, I can simply supply a quick set of instructions as part of the parameter call. This ends up saving me from writing a whole bunch of code, while still getting the same results in the end.

The following is an example of using a closure as a function parameter. This example sets up a dictionary of family members, then maps the against an array of family members to report what their roles are. We’re using the existing map() function, and passing a number of parameter options through to it from the people array.

This is how I would write the above scenario without a closure. I would create a for .. in loop for the people array, then check each entry using a function call. I’ve emphasized the relevant code in the examples below.

[swift] let myFamily = [ "Kirsten":"Wife", "Chance":"Son", "Barry":"Dad", "Lynette":"Mom", "Susan":"Sister", "Michael":"Brother in Law", "Sierra":"Niece", "Georgia":"Niece", "Carol":"Mother in Law", "John":"Father in Law", "Natalie":"Sister in Law", "Nathan":"Brother in Law", "Delmar":"Brother in Law", ] let people = [ "Kirsten", "Chance", "Barry" ] func whois (nametoCheck: String) { for (familyName, role) in myFamily { if (familyName == nametoCheck) { println("\(nametoCheck) is my \(role)") } } } for person in people { whois(person) } [/swift]

Here is how we might express the same thing as a closure. When the below code is run, it prints “Kirsten is my Wife. Chance is my Son. Barry is my Dad."

[swift] let myFamily = [ "Kirsten":"Wife", "Chance":"Son", "Barry":"Dad", "Lynette":"Mom", "Susan":"Sister", "Michael":"Brother in Law", "Sierra":"Niece", "Georgia":"Niece", "Carol":"Mother in Law", "John":"Father in Law", "Natalie":"Sister in Law", "Nathan":"Brother in Law", "Delmar":"Brother in Law", ] let people = [ "Kirsten", "Chance", "Barry" ] let relations = people.map({(person: String) -> String in "\(person) is my \(myFamily[person]!)."}) println(relations) [/swift]

As you can see, we’ve turned 11 lines of code into 2. This is a much more efficient expression of what we’re trying to do, using a pre-existing function that we don’t have to write ourselves. Now, of course, I would tend to break the closure across several lines of code to make the code easier to read. In the end, it would look like the following:

[swift] let relations = people.map({ (person: String) -> String in "\(person) is my \(myFamily[person]!)" }) [/swift]

Here’s another excellent example, adapted from Rob Percival’s Complete iOS 8 and Swift Course. This example takes a URL string creates a data task for that URL, and defines what to do with that data within the closure.

[swift] // define a URL var url = NSURL(string: "http://staticred.net/index.xml") // Create a NSURL session with that URL. let task = NSURLSession.sharedSession().dataTaskWithURL(url!){(data, response, error) in // encodes the raw data into UTF8 string data. println(NSString(data: data, encoding:NSUTF8StringEncoding)) } // "Resume" the NSURL session. Data comes from remote site. task.resume() [/swift]

This shows closures being used as a sort of shorthand within Swift, allowing you to compress code into its most efficient form.

Using nested functions

The other use pattern for closures in Swift appears to be nested functions. In earlier versions of the Swift language, there did not appear to be any way to mark a method as private. All functions defined within a file were available to the application regardless of where they were being called from and—more importantly —meant that any function defined within a class was available to any objet created from that class. Nested functions are only available with the function they are defined within.

This is quite different from a number of other object oriented programming languages, where methods and attributes can be assigned scope within the class definition. For example, in PHP, you can mark a method or attribute as public (available outside the class), private (only available within the class) or protected (available only inside the class or within any child classes).

When defining an object class, there are often times where want to create methods that are specific to dealing with data inside of the class, but are either not useful outside of that class, or are dangerous to expose to other areas of the application. In an object oriented language that supports method and attribute scoping within a class definition, this is fairly easily accomplished. For example, in PHP, I might write the following class:

[php] class User { // This is a public variable, which can be accessed outside of the class. public $username; public $password; // This is a private variable, which can not be accessed outside // of the class. private $salt = "BF5d324#$kLa0d4!"; // This is a public method, which can be accessed outside of the class. public function login() { ... code ... } public function create_user() { ... code ... $this->storePassword(); } // This is a private method, which can not be accessed outside // of the class. private function storePassword() { ... code ... $encrypted_password = crypt($this->password, $this->salt); } } // Create a new object from the myClass class $myUser = new User(); // These are valid statements $myUser->username = "darren"; $myUser->password = "password"; $myUser->login(); // These are invalid statements, because the methods are not accessible // outside of the class. $myUser->salt = "thisismysalt"; $myUser->storePassword(); [/php]

Because this scoping was missing from early versions of the Swift programming language, nested functions were used as a kind of workaround. Nested functions were a way of mimicking the private methods found in other langauages.

With newer releases of Swift, however, object classes can now include scope definitions when creating methods. Although the concept of a protected method does not yet exist, it is simple to denote a public or private method within a Swift class, by simply beginning the func statement with either “public”, “Internal”, or "private."

The following is a description of Swift’s access levels from the Swift documentation:

Public access enables entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use public access when specifying the public interface to a framework.

Internal access enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.

Private access restricts the use of an entity to its own defining source file. Use private access to hide the implementation details of a specific piece of functionality.

[Source]

 

We could rewrite the above PHP code like the following:

[swift] public class User { // This are public variables, which can be accessed outside of the class. public var username = "" public var password = "" // This is a private variable, which can not be accessed outside of the class. private let salt= "BF5d324#$kLa0d4!" // These are public functions, which can be accessed outside of the class. public func login() { // ... code... } public func create_user() -> Bool { // ... code... } // This is a private function, which can not be accessed outside of the class. private func store_password() -> Bool { // ... code... } } // These are valid statements var myUser = User() myUser.username = "darren" myUser.password = "password" myUser.login() // These are invalid statements myUser.salt = "thisismysalt" let storedPassword = myUser.store_password() [/swift]

As always, if you have any questions, comments, or corrections, drop me a line on Twitter @staticred.