This is an introductory explanation of the Swift 3 programming language as it relates to practical real-life iOS programming. Copyright 2016 Matt Neuburg. It constitutes a portion of my book, iOS 10 Programming Fundamentals with Swift. If you find these excerpts useful, please consider buying the book!

Chapter 5. Flow Control and More

This chapter is a miscellany, presenting various remaining aspects of the Swift language. I’ll start by describing the syntax of Swift’s flow control constructs for branching, looping, and jumping. Then I’ll talk about how to override operators and how to create your own operators. The chapter ends with a survey of Swift’s privacy and introspection features, and some specialized modes of reference type memory management.

Flow Control

A computer program has a path of execution through its code statements. Normally, this path follows a simple rule: execute each statement in succession. But there is another possibility. Flow control can be used to make the path of execution skip some code statements, or repeat some code statements. Flow control is what makes a computer program “intelligent,” and not merely a simple fixed sequence of steps. By testing the truth value of a condition — an expression that evaluates to a Bool and is thus true or false — the program decides at that moment how to proceed. Flow control based on testing a condition may be divided into two general types:

Branching
The code is divided into alternative chunks, like roads that diverge in a wood, and the program is presented with a choice of possible ways to go: the truth of a condition is used to determine which chunk will actually be executed.
Looping
A chunk of code is marked off for possible repetition: the truth of a condition is used to determine whether the chunk should be executed, and then whether it should be executed again. Each repetition is called an iteration. Typically, some feature of the environment (such as the value of a variable) is changed on each iteration, so that the repetitions are not identical, but are successive stages in progressing through an overall task.

The chunks of code in flow control, which I refer to as blocks, are demarcated by curly braces. These curly braces constitute a scope. New local variables can be declared here, and go out of existence automatically when the path of execution exits the curly braces (Chapter 3). For a loop, this means that local variables come into existence and go out of existence on each iteration. As with any scope, code inside the curly braces can see the surrounding higher scope (Chapter 1).

Swift flow control is fairly simple, and by and large is similar to flow control in C and related languages. There are two fundamental syntactic differences between Swift and C, both of which make Swift simpler and clearer: in Swift, a condition does not have to be wrapped in parentheses, and the curly braces can never be omitted. Moreover, Swift adds some specialized flow control features to help you grapple more conveniently with Optionals, and boasts a particularly powerful form of switch statement.

Branching

Swift has two forms of branching: the if construct, and the switch statement. I’ll also discuss conditional evaluation, a compact form of if construct.

If construct

The Swift branching construct with if is similar to C. Many examples of if constructs have appeared already in this book. The construct may be formally summarized as shown in Example 5.1.

Example 5.1. The Swift if construct

if condition {
    statements
}

if condition {
    statements
} else {
    statements
}

if condition {
    statements
} else if condition {
    statements
} else {
    statements
}

The third form, containing else if, can have as many else if blocks as needed, and the final else block may be omitted.

Here’s a real-life if construct that lies at the heart of one of my apps:

// okay, we've tapped a tile; there are three cases
if self.selectedTile == nil { // no selected tile: select and play this tile
    self.select(tile:tile)
    self.play(tile:tile)
} else if self.selectedTile == tile { // selected tile tapped: deselect it
    self.deselectAll()
    self.player?.pause()
} else { // there was a selected tile, another tile was tapped: swap them
    self.swap(self.selectedTile, with:tile, check:true, fence:true)
}

Conditional binding

In Swift, if can be followed immediately by a variable declaration and assignment — that is, by let or var and a new local variable name, possibly followed by a colon and a type declaration, then an equal sign and a value. This syntax, called a conditional binding, is actually a shorthand for conditionally unwrapping an Optional. The assigned value is expected to be an Optional — the compiler will stop you if it isn’t — and this is what happens:

  • If the Optional is nil, the condition fails and the block is not executed.
  • If the Optional is not nil, then:

    1. The Optional is unwrapped.
    2. The unwrapped value is assigned to the declared local variable.
    3. The block is executed with the local variable in scope.

Thus, a conditional binding is a convenient shorthand for safely passing an unwrapped Optional into a block. The Optional is unwrapped, and the block is executed, only if the Optional can be unwrapped.

It is perfectly reasonable for the local variable in a conditional binding to have the same name as an existing variable in the surrounding scope. It can even have the same name as the Optional being unwrapped! There is then no need to make up a new name, and inside the block the unwrapped value of the Optional overshadows the original Optional, which thus cannot be accessed accidentally.

Here’s an example of a conditional binding. Recall this code from Chapter 4, where I optionally unwrap a Notification’s userInfo dictionary, attempt to fetch a value from the dictionary using the "progress" key, and proceed only if that value turns out to be an NSNumber:

let prog = (n.userInfo?["progress"] as? NSNumber)?.doubleValue
if prog != nil {
    self.progress = prog!
}

We can rewrite that code as a conditional binding:

if let prog = (n.userInfo?["progress"] as? NSNumber)?.doubleValue {
    self.progress = prog
}

It is also possible to nest conditional bindings. To illustrate, I’ll rewrite the previous example to use a separate conditional binding for every Optional in the chain:

if let ui = n.userInfo {
    if let prog = ui["progress"] as? NSNumber {
        self.progress = prog.doubleValue
    }
}

The result, if the chain involves many optional unwrappings, can be somewhat verbose and the nest can become deeply indented — Swift programmers like to call this the “pyramid of doom” — but in my view it is also considerably more legible, because the structure reflects perfectly the successive stages of testing. To help avoid the indentation, successive conditional bindings can be combined into a condition list, with each condition separated by comma:

if let ui = n.userInfo, let prog = ui["progress"] as? NSNumber {
    self.progress = prog.doubleValue
}

In that code, the assignment to prog won’t even be attempted if the assignment to ui fails (because n.userInfo is nil).

Condition lists do not have to consist solely of conditional bindings. They can include ordinary conditions. The important thing is the left-to-right order of evaluation, which allows each condition to depend upon the previous one. Here’s a real-life example from my own code. The “pyramid of doom” consists of four nested conditions:

override func observeValue(forKeyPath keyPath: String?,
    of object: Any?, change: [NSKeyValueChangeKey : Any]?,
    context: UnsafeMutableRawPointer?) {
        if keyPath == readyForDisplay {
            if let obj = object as? AVPlayerViewController {
                if let ok = change?[.newKey] as? Bool {
                    if ok {
                        // ...
                    }
                }
            }
        }
}

Alternatively, those four conditions can be combined into a single list:

override func observeValue(forKeyPath keyPath: String?,
    of object: Any?, change: [NSKeyValueChangeKey : Any]?,
    context: UnsafeMutableRawPointer?) {
        if keyPath == readyForDisplay,
        let obj = object as? AVPlayerViewController,
        let ok = change?[.newKey] as? Bool,
        ok {
            // ...
        }
}

But whether the second version is more legible is an open question.

Alternatively, you can express the chain of conditions as a series of guard statements (see Guard); I think I like this idiom best:

override func observeValue(forKeyPath keyPath: String?,
    of object: Any?, change: [NSKeyValueChangeKey : Any]?,
    context: UnsafeMutableRawPointer?) {
        guard keyPath == readyForDisplay else {return}
        guard let obj = object as? AVPlayerViewController else {return}
        guard let ok = change?[.newKey] as? Bool else {return}
        guard ok else {return}
        // ...
}

Switch statement

A switch statement is a neater way of writing an extended if...else if...else construct. In C (and Objective-C), a switch statement contains hidden traps; Swift eliminates those traps, and adds power and flexibility. As a result, switch statements are commonly used in Swift (whereas they are relatively rare in my Objective-C code).

In a switch statement, the condition involves the comparison of different possible values, called cases, against a single value, called the tag. The case comparisons are performed successively in order. As soon as a case comparison succeeds, that case’s code is executed and the entire switch statement is exited. The schema is shown in Example 5.2; there can be as many cases as needed, and the default case can be omitted (subject to restrictions that I’ll explain in a moment).

Example 5.2. The Swift switch statement

switch tag {
case pattern1:
    statements
case pattern2:
    statements
default:
    statements
}

Here’s an actual example:

switch i {
case 1:
    print("You have 1 thingy!")
case 2:
    print("You have 2 thingies!")
default:
    print("You have \(i) thingies!")
}

In that code, a variable i functions as the tag. The value of i is first compared to the value 1. If it is 1, that case’s code is executed and that’s all. If it is not 1, it is compared to the value 2. If it is 2, that case’s code is executed and that’s all. If the value of i matches neither of those, the default case’s code is executed.

In Swift, a switch statement must be exhaustive. This means that every possible value of the tag must be covered by a case. The compiler will stop you if you try to violate this rule. The rule makes intuitive sense when a value’s type allows only a limited number of possibilities; the usual example is an enum, which itself has a small, fixed set of cases as its possible values. But when, as in the preceding example, the tag is an Int, there is an infinite number of possible individual cases. Thus, a “mop-up” case must appear, to mop up all the cases that you didn’t write explicitly. A common way to write a “mop-up” case is to use a default case.

Each case’s code can consist of multiple lines; it doesn’t have to be a single line, as the cases in the preceding example happen to be. However, it must consist of at least a single line; it is illegal for a Swift switch case to be completely empty. It is legal for the first (or only) line of a case’s code to appear on the same line as the case, after the colon; thus, I could have written the preceding example like this:

switch i {
case 1: print("You have 1 thingy!")
case 2: print("You have 2 thingies!")
default: print("You have \(i) thingies!")
}

The minimum single line of case code is the keyword break; used in this way, break acts as a placeholder meaning, “Do nothing.” It is very common for a switch statement to include a default (or other “mop-up” case) consisting of nothing but the keyword break; in this way, you exhaust all possible values of the tag, but if the value is one that no case explicitly covers, you do nothing.

Now let’s focus on the comparison between the tag value and the case value. In the preceding example, it works like an equality comparison (==); but that isn’t the only possibility. In Swift, a case value is actually a special expression called a pattern, and the pattern is compared to the tag value using a “secret” pattern-matching operator, ~=. The more you know about the syntax for constructing a pattern, the more powerful your case values and your switch statements will be.

A pattern can include an underscore (_) to absorb all values without using them. An underscore case is thus an alternative form of “mop-up” case:

switch i {
case 1:
    print("You have 1 thingy!")
case _:
    print("You have many thingies!")
}

A pattern can include a declaration of a local variable name (an unconditional binding) to absorb all values and use the actual value. This is another alternative form of “mop-up” case:

switch i {
case 1:
    print("You have 1 thingy!")
case let n:
    print("You have \(n) thingies!")
}

When the tag is a Comparable, a case can include a Range; the test involves sending the Range the contains message:

switch i {
case 1:
    print("You have 1 thingy!")
case 2...10:
    print("You have \(i) thingies!")
default:
    print("You have more thingies than I can count!")
}

When the tag is an Optional, a case can test it against nil. Thus, a possible way to unwrap an Optional safely is to test against nil first and then unwrap in a subsequent case, since we’ll never reach the unwrapping if the nil test succeeds. In this example, i is an Optional wrapping an Int:

switch i {
case nil: break
default:
    switch i! {
    case 1:
        print("You have 1 thingy!")
    case let n:
        print("You have \(n) thingies!")
    }
}

That seems a bit clumsy, however, so there’s a special syntax: appending ? to a case pattern safely unwraps an Optional tag. Thus, we can rewrite that example like this:

switch i {
case 1?:
    print("You have 1 thingy!")
case let n?:
    print("You have \(n) thingies!")
case nil: break
}

When the tag is a Bool, a case can test it against a condition. Thus, by a clever perversion, you can use the cases to test any conditions you like — by using true as the tag! A switch statement thus becomes a genuine substitute for an extended if...else if construct. In this example from my own code, I could have used if...else if, but each case is just one line, so a switch statement seems clearer:

func position(for bar: UIBarPositioning) -> UIBarPosition {
    switch true {
    case bar === self.navbar:  return .topAttached
    case bar === self.toolbar: return .bottom
    default:                   return .any
    }
}

A pattern can include a where clause adding a condition to limit the truth value of the case. This is often, though not necessarily, used in combination with a binding; the condition can refer to the variable declared in the binding:

switch i {
case let j where j < 0:
    print("i is negative")
case let j where j > 0:
    print("i is positive")
case 0:
    print("i is 0")
default:break
}

A pattern can include the is operator to test the tag’s type. In this example, assume that we have a Dog class and its NoisyDog subclass, and that d is typed as Dog:

switch d {
case is NoisyDog:
    print("You have a noisy dog!")
case _:
    print("You have a dog.")
}

A pattern can include a cast with the as (not as?) operator. Typically, you’ll combine this with a binding that declares a local variable; despite the use of unconditional as, the value is conditionally cast and, if the cast succeeds, the local variable carries the cast value into the case code. Again, d is typed as Dog; assume that Dog implements bark and that NoisyDog implements beQuiet:

switch d {
case let nd as NoisyDog:
    nd.beQuiet()
case let d:
    d.bark()
}

You can also use as (not as?) to cast down the tag (and possibly unwrap it) conditionally as part of a test against a specific match; in this example, i might be an Any or an Optional wrapping an Any:

switch i {
case 0 as Int:
    print("It is 0")
default:break
}

You can perform multiple tests at once by expressing the tag as a tuple and wrapping the corresponding tests in a tuple. The case passes only if every test in the test tuple succeeds against the corresponding member of the tag tuple. In this example, we start with a dictionary d typed as [String:Any]. Using a tuple, we can safely attempt to extract and cast two values at once:

switch (d["size"], d["desc"]) {
case let (size as Int, desc as String):
    print("You have size \(size) and it is \(desc)")
default:break
}

When a tag is an enum, the cases can be cases of the enum. A switch statement is thus an excellent way to handle an enum. Here’s the Filter enum:

enum Filter {
    case albums
    case playlists
    case podcasts
    case books
}

And here’s a switch statement, where the tag, type, is a Filter; no mop-up is needed, because I’ve exhausted the cases:

switch type {
case .albums:
    print("Albums")
case .playlists:
    print("Playlists")
case .podcasts:
    print("Podcasts")
case .books:
    print("Books")
}

A switch statement provides a way to extract an associated value from an enum case. Recall this enum from Chapter 4:

enum Error {
    case number(Int)
    case message(String)
    case fatal
}

To extract the error number from an Error whose case is .number, or the message string from an Error whose case is .message, I can use a switch statement. Recall that the associated value is actually a tuple. A tuple of patterns after the matched case name is applied to the associated value. If a pattern is a binding variable, it captures the associated value. The let (or var) can appear inside the parentheses or after the case keyword; this code illustrates both alternatives:

switch err {
case .number(let theNumber):
    print("It is a number: \(theNumber)")
case let .message(theMessage):
    print("It is a message: \(theMessage)")
case .fatal:
    print("It is fatal")
}

If the let (or var) appears after the case keyword, I can add a where clause:

switch err {
case let .number(n) where n > 0:
    print("It's a positive error number \(n)")
case let .number(n) where n < 0:
    print("It's a negative error number \(n)")
case .number(0):
    print("It's a zero error number")
default:break
}

If I don’t want to extract the error number but just want to match against it, I can use some other pattern inside the parentheses:

switch err {
case .number(1...Int.max):
    print("It's a positive error number")
case .number(Int.min...(-1)):
    print("It's a negative error number")
case .number(0):
    print("It's a zero error number")
default:break
}

This same pattern also gives us yet another way to deal with an Optional tag. An Optional, as I explained in Chapter 4, is in fact an enum. It has two cases, .none and .some, where the wrapped value is the .some case’s associated value. But now we know how to extract the associated value! Thus we can rewrite yet again the earlier example where i is an Optional wrapping an Int:

switch i {
case .none: break
case .some(1):
    print("You have 1 thingy!")
case .some(let n):
    print("You have \(n) thingies!")
}

When all you want to do is extract an associated value from an enum, a full switch statement may seem a bit heavy-handed. The lightweight if case construct lets you use in a condition the same sort of pattern syntax you’d use in a case of a switch statement. Where a switch case pattern is compared against a previously stated tag, an if case pattern is followed by an equal sign and the tag. Thus, for example, this is another way to extract an associated value from an enum; err is our Error enum once again:

if case let .number(n) = err {
    print("The error number is \(n)")
}

The condition starting with case is a condition like any other, and can be part of a longer comma-separated condition list:

if case let .number(n) = err, n < 0 {
    print("The negative error number is \(n)")
}

To combine switch case tests (with an implicit logical-or), separate them with a comma:

switch i {
case 1,3,5,7,9:
    print("You have a small odd number of thingies.")
case 2,4,6,8,10:
    print("You have a small even number of thingies.")
default:
    print("You have too many thingies for me to count.")
}

In this example, i is declared as an Any:

switch i {
case is Int, is Double:
    print("It's some kind of number.")
default:
    print("I don't know what it is.")
}

New in Swift 3, a comma can even combine patterns that declare binding variables, provided they declare the same variable of the same type:

switch err {
case let .number(n) where n > 0, let .number(n) where n < 0:
    print("It's a nonzero error number \(n)")
case .number(0):
    print("It's a zero error number")
default:break
}

Another way of combining cases is to jump from one case to the next by using a fallthrough statement. When a fallthrough statement is encountered, the current case code is aborted immediately and the next case code runs unconditionally. The test of the next case is not performed, so the next case can’t declare any binding variables, because they would never be set. It is not uncommon for a case to consist entirely of a fallthrough statement:

switch pep {
case "Manny": fallthrough
case "Moe": fallthrough
case "Jack":
    print("\(pep) is a Pep boy")
default:
    print("I don't know who \(pep) is")
}

Conditional evaluation

An interesting problem arises when you’d like to decide what value to use — for example, what value to assign to a variable. This seems like a good use of a branching construct. You can, of course, declare the variable first without initializing it, and then set it from within a subsequent branching construct. It would be nice, however, to use a branching construct as the variable’s value. Here, for example, I try (and fail) to write a variable assignment where the equal sign is followed directly by a branching construct:

let title = switch type { // compile error
case .albums:
    "Albums"
case .playlists:
    "Playlists"
case .podcasts:
    "Podcasts"
case .books:
    "Books"
}

There are languages that let you talk that way, but Swift is not one of them. However, an easy workaround does exist — use a define-and-call anonymous function, as I suggested in Chapter 2:

let title : String = {
    switch type {
    case .albums:
        return "Albums"
    case .playlists:
        return "Playlists"
    case .podcasts:
        return "Podcasts"
    case .books:
        return "Books"
    }
}()

In the special case where a value can be decided by a two-pronged condition, Swift provides the C ternary operator (:?). Its scheme is as follows:

condition ? exp1 : exp2

If the condition is true, the expression exp1 is evaluated and the result is used; otherwise, the expression exp2 is evaluated and the result is used. Thus, you can use the ternary operator while performing an assignment, using this schema:

let myVariable = condition ? exp1 : exp2

What myVariable gets initialized to depends on the truth value of the condition. I use the ternary operator heavily in my own code. Here’s an example:

cell.accessoryType =
    ix.row == self.currow ? .checkmark : .disclosureIndicator

The context needn’t be an assignment; here, we’re deciding what value to pass as a function argument:

context.setFillColor(self.hilite ? purple.cgColor : beige.cgColor)

The ternary operator can also be used to determine the receiver of a message. In this example, one of two UIViews will have its background color set:

(self.firstRed ? v1 : v2).backgroundColor = .red

In Objective-C, there’s a collapsed form of the ternary operator that allows you to test a value against nil. If it is nil, you get to supply a substitute value. If it isn’t nil, the tested value itself is used. In Swift, the analogous operation would involve testing an Optional: if the tested Optional is nil, use the substitute value; if it isn’t nil, unwrap the Optional and use the unwrapped value. Swift has such an operator — the ?? operator (called the nil-coalescing operator).

In this example, arr is a Swift array of Optional strings, and I’m converting it to a form that can be processed by a method written in Objective-C. An Objective-C NSArray can’t contain nil, so Cocoa provides a special class, NSNull, whose singleton instance, NSNull(), can stand in for nil where an object is needed. So I propose to unwrap those Optional strings that aren’t nil and substitute NSNull() for those that are. Here’s a perfectly effective implementation:

let arr2:[Any] = arr.map {if $0 != nil {return $0!} else {return NSNull()}}

But we can write the same thing much more neatly using the ternary operator:

let arr2 = arr.map {$0 != nil ? $0! : NSNull() as Any}

And the nil-coalescing operator is even neater:

let arr2 = arr.map {$0 ?? NSNull() as Any}

Expressions using ?? can be chained:

let someNumber = i1 as? Int ?? i2 as? Int ?? 0

That code tries to cast i1 to an Int and use that Int. If that fails, it tries to cast i2 to an Int and use that Int. If that fails, it gives up and uses 0.

Loops

The usual purpose of a loop is to repeat a block of code with some simple difference on each iteration. This difference will typically serve also as a signal for when to stop the loop. Swift provides two basic loop structures: while loops and for loops.

While loops

A while loop comes in two forms, schematized in Example 5.3.

Example 5.3. The Swift while loop

while condition {
    statements
}

repeat {
    statements
} while condition

The chief difference between the two forms is the timing of the test. In the second form, the condition is tested after the block has executed — meaning that the block will be executed at least once.

Usually, the code inside the block will change something that alters both the environment and the condition, thus eventually bringing the loop to an end. Here’s a typical example from my own code (movenda is an array):

while self.movenda.count > 0 {
    let p = self.movenda.removeLast()
    // ...
}

Each iteration removes an element from movenda, so eventually its count falls to 0 and the loop is no longer executed; execution then proceeds to the next line after the closing curly braces.

The first form of while loop can involve a conditional binding of an Optional. This provides a compact way of safely unwrapping an Optional and looping until the Optional is nil; the local variable containing the unwrapped Optional is in scope inside the curly braces. Thus, my code can be rewritten more compactly:

while let p = self.movenda.popLast() {
    // ...
}

There is no Swift repeat...until construct; instead, negate the while condition. In my own code, for example, I commonly need to walk my way up or down a hierarchy. Here, textField is a subview, at some depth, of some table view cell, and I want to know which table view cell it is a subview of. So I keep walking up the view hierarchy, investigating each superview in turn, until either I reach a table view cell or I hit the top of the view hierarchy:

var v : UIView? = textField
repeat {v = v?.superview} while !(v is UITableViewCell || v == nil)
if let c = v as? UITableViewCell {
    // ... if we get here, c is the cell
}

Similar to the if case construct, while case lets you use a switch case pattern. In this rather artificial example, we have an array of various Error enums:

let arr : [Error] = [
    .message("ouch"), .message("yipes"), .number(10), .number(-1), .fatal
]

We can extract the .message associated string values from the start of the array, like this:

var i = 0
while case let .message(message) = arr[i]  {
    print(message) // "ouch", then "yipes"; then the loop stops
    i += 1
}

For loops

The Swift for loop is schematized in Example 5.4.

Example 5.4. The Swift for loop

for variable in sequence {
    statements
}

The for...in construct that forms the basis of Swift’s for loop is similar to Objective-C’s for...in construct. In Objective-C, this syntax is available whenever a class conforms to the NSFastEnumeration protocol. In Swift, it is available whenever a type adopts the Sequence protocol.

In the for...in construct, the variable is implicitly declared with let on each iteration; it is thus immutable by default. (If you need to assign to the variable within the block, write for var.) The variable is also local to the block. On each iteration, a successive element of the sequence is used to initialize the variable, which is then in scope inside the block.

A common use of for loops is to iterate through successive numbers. This is easy in Swift, because you can readily create a sequence of numbers on the fly — a Range:

for i in 1...5 {
    print(i)
}

Under the hood, a Sequence has a makeIterator method which yields an iterator object adopting IteratorProtocol. According to this protocol, the iterator has a mutating next method that returns the next object in the sequence wrapped in an Optional, or nil if there is no next object. Thus, for...in is actually a kind of while loop:

var g = (1...5).makeIterator()
while let i = g.next() {
    print(i)
}

Sometimes you may find that writing out the while loop explicitly in that way makes the loop easier to control and to customize.

The sequence will often be an existing value. It might be a character sequence, in which case the variable values are the successive Characters. It might be an array, in which case the variable values are the successive elements of the array. It might be a dictionary, in which case the variable values are key–value tuples, and you will probably express the variable as a tuple of two names in order to capture them. Many examples have already appeared in earlier chapters.

As I explained in Chapter 4, you may encounter an array coming from Objective-C whose elements will need to be cast down from Any. It is quite typical to do this as part of the sequence specification:

let p = Pep()
for boy in p.boys() as! [String] {
    // ...
}

The sequence enumerated method yields a succession of tuples preceding each element of the original sequence with its index number:

for (i,v) in self.tiles.enumerated() {
    v.center = self.centers[i]
}

If you need to skip some values of the sequence, you can append a where clause:

for i in 0...10 where i % 2 == 0 {
    print(i) // 0, 2, 4, 6, 8, 10
}

Like if case and while case, there’s also for case, letting us use a switch case pattern in a for loop. The tag is each successive value of the sequence, so no assignment operator is used. Return to our example of an array of Error enums:

let arr : [Error] = [
    .message("ouch"), .message("yipes"), .number(10), .number(-1), .fatal
]

Here we cycle through the whole array, extracting just the .number associated values:

for case let .number(i) in arr {
    print(i) // 10, -1
}

Similarly, here’s how to work safely with an array each of whose elements might or might not be castable to a certain type:

let arr : [Any] = ["hey", 1, "ho"]
for case let s as String in arr {
    print(s) // hey, ho
}

A sequence also has instance methods, such as map(_:), filter(_:), and reversed; you can apply these to hone the sequence through which we will cycle. In this example, I count backward by even numbers:

let range = (0...10).reversed().filter{$0 % 2 == 0}
for i in range {
    print(i) // 10, 8, 6, 4, 2, 0
}

Yet another approach is to generate the sequence by calling stride(from:through:by) or stride(from:to:by:). These are global functions whose first parameter must adopt the Strideable protocol, which is adopted by numeric types and anything else that can be incremented and decremented. Which form you use depends on whether or not you want the sequence to include the final value. The by: argument can be negative:

for i in stride(from: 10, through: 0, by: -2) {
    print(i) // 10, 8, 6, 4, 2, 0
}

For maximum flexibility, you can use the global sequence function (new in Swift 3) to generate your sequence by rule. It takes two parameters — an initial value, and a generation function that returns the next value based on what has gone before. In theory, the sequence generated by the sequence function can be infinite in length — though this is not a problem, because the resulting sequence is “lazy,” meaning that an element isn’t generated until you ask for it. In reality, you’ll use one of two techniques to limit the result. The generation function can limit the sequence by returning nil to signal that the end has been reached:

let seq = sequence(first:1) {$0 >= 10 ? nil : $0 + 1}
for i in seq {
    print(i) // 1,2,3,4,5,6,7,8,9,10
}

Alternatively you can request just a piece of the infinite sequence — for example, by cycling through the sequence for a while and then stopping, or by taking a finite prefix:

let seq = sequence(first:1) {$0 + 1}
for i in seq.prefix(5) {
    print(i) // 1,2,3,4,5
}

The sequence function comes in two forms. The first form, sequence(first:next:), initially hands first into the next: function and subsequently hands the previous result of the next: function into the next: function, as illustrated in the preceding examples. The second form, sequence(state:next:), is more general: it repeatedly hands state into the next: function as an inout parameter; the next: function is expected to set that parameter, using it as a scratchpad, in addition to returning the next value in the sequence. An obvious illustration is the Fibonacci sequence:

let fib = sequence(state:(0,1)) {
    (pair: inout (Int,Int)) -> Int in
    let n = pair.0 + pair.1
    pair = (pair.1,n)
    return n
}
for i in fib.prefix(10) {
    print(i) // 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
}

You can cycle through two sequences simultaneously using the global zip function, which takes two sequences and yields a Zip2Sequence struct, which is itself a sequence. The value on each iteration through a Zip2Sequence is a tuple of the corresponding elements from both original sequences; if one of the original sequences is longer than the other, the extra elements are ignored:

let arr1 = ["CA", "MD", "NY", "AZ"]
let arr2 = ["California", "Maryland", "New York"]
var d = [String:String]()
for (s1,s2) in zip(arr1,arr2) {
    d[s1] = s2
} // now d is ["MD": "Maryland", "NY": "New York", "CA": "California"]

Jumping

Although branching and looping constitute the bulk of the decision-making flow of code execution, sometimes even they are insufficient to express the logic of what needs to happen next. On certain occasions, it is useful to be able to interrupt your code’s progress completely and jump to a different place within it.

The most general way to jump from anywhere to anywhere is the goto command, common in early programming languages, but now notoriously “considered harmful.” Swift doesn’t have a goto command, but it does provide a repertory of controlled ways of jumping, which will, in practice, cover any real-life situation. Swift’s modes of jumping are all forms of early exit from the current flow of code.

Shortcircuiting and labels

One of the most important constructs in Swift is the function call (Chapter 2). One function calls another, which may call another, and so on, forming a call stack. When a return statement is encountered, accompanied by a return value if needed, execution of the function code is aborted immediately and the path of execution comes back to the point at which the call is made. In effect, we have jumped one level up the call stack.

Swift also has several ways of shortcircuiting the flow of branch and loop constructs:

fallthrough
A fallthrough statement in a switch case aborts execution of the current case code and immediately begins executing the code of the next case. There must be a next case or the compiler will stop you.
continue

A continue statement in a loop construct aborts execution of the current iteration and proceeds to the next iteration:

  • In a while loop, continue means to perform immediately the conditional test.
  • In a for loop, continue means to proceed immediately to the next iteration if there is one.
break

A break statement aborts the current construct:

  • In a loop, break aborts the loop completely.
  • In the code of a switch case, break aborts the entire switch construct.

When constructs are nested, you may need to specify which construct you want to continue or break. Therefore, Swift permits you to put a label before the start of a do block, an if construct, a switch statement, a while loop, or a for loop. The label is an arbitrary name followed by a colon. You can then use that label name as a second term in a continue or break statement within the labeled construct at any depth, to specify that this is the construct you are referring to.

Here’s an artificial example to illustrate the syntax. First, I’ll nest two for loops with no label:

for i in 1...5 {
    for j in 1...5 {
        print("\(i), \(j);")
        break
    }
}
// 1, 1; 2, 1; 3, 1; 4, 1; 5, 1;

As you can see from the output, that code keeps aborting the inner loop after one iteration, while the outer loop proceeds normally through all five iterations. But what if you wanted to abort the entire nested construct? The solution is a label:

outer: for i in 1...5 {
    for j in 1...5 {
        print("\(i), \(j);")
        break outer
    }
}
// 1, 1;

Throwing and catching errors

Sometimes a situation arises where further coherent progress is impossible: the entire operation in which we are engaged has failed. It can then be desirable to abort the current scope, and possibly the current function, and possibly even the function that called it, and so on, exiting to a point where we can acknowledge this failure and proceed in good order in some other way.

For this purpose, Swift provides a mechanism for throwing and catching errors. In keeping with its usual insistence on safety and clarity, Swift imposes certain strict conditions on the use of this mechanism, and the compiler will ensure that you adhere to them.

An error, in this sense, is a kind of message, presumably indicating what went wrong. This message is passed up the nest of scopes and function calls as part of the error-handling process, and the code that recovers from the failure can, if desired, read the message and determine how to proceed.

In Swift, an error must be an object of a type that adopts the Error protocol, which has just two requirements: a String _domain property and an Int _code property. The purpose of those properties is to help errors cross the bridge between Swift and Objective-C; in real life, you will be unaware of them (and in fact you won’t even see them listed in the Swift header). What you will see and use will be one of the following:

A Swift type that adopts Error
As soon as a Swift type formally declares adoption of the Error protocol, it is ready to be used as an error object; the protocol requirements are magically fulfilled for you, behind the scenes. Typically, this type will be an enum, which will communicate its message by means of its cases: different cases will distinguish different kinds of possible failure, perhaps with raw values or associated types to carry further information.
NSError
NSError is Cocoa’s class for communicating the nature of a problem; Swift extends NSError to adopt Error and bridges them to one another. If your call to a Cocoa method generates a failure, Cocoa will send you an NSError instance typed as an Error; you can examine its properties, such as its domain, code, localizedDescription, and so forth, to learn what went wrong and to present a coherent alert to the user. You can also create your own NSError instance by calling its designated initializer, init(domain:code:userInfo:).

There are two stages of the error mechanism to consider: throwing an error, and catching an error. Throwing an error aborts the current path of execution and hands an error object to the error mechanism. Catching an error receives that error object from the error mechanism and responds in good order, with the path of execution resuming after the point of catching. In effect, we have jumped from the throwing point to the catching point.

To throw an error, use the keyword throw followed by an error object. That’s all it takes! The current block of code is immediately aborted, and the error mechanism takes over. However, to ensure that the throw command is used coherently, Swift imposes a rule that you can say throw only in a context where the error can be caught. What is such a context?

The primary context for throwing and catching an error is the do...catch construct. This consists of a do block and one or more catch blocks. It is legal to throw in the do block; an accompanying catch block can then be fed any errors thrown from within the do block. The do...catch construct’s schema looks like Example 5.5.

Example 5.5. The Swift do...catch construct

do {
    statements // a throw can happen here
} catch errortype {
    statements
} catch {
    statements
}

A single do block can be accompanied by multiple catch blocks. Catch blocks are like the cases of a switch statement, and will usually have the same logic: first, you might have specialized catch blocks, each of which is designed to handle some limited set of possible errors; finally, you might have a general catch block that acts as the default, mopping up any errors that were not caught by any of the specialized catch blocks.

In fact, the syntax used by a catch block to specify what sorts of error it catches is the pattern syntax used by a case in a switch statement! Imagine that this is a switch statement, and that the tag is the error object. Then the matching of that error object to a particular catch block is performed just as if you had written case instead of catch. Typically, when the Error is an enum, a specialized catch block will state at least the enum that it catches, and possibly also the case of that enum; it can have a binding, to capture the enum or its associated type; and it can have a where clause to limit the possibilities still further.

To illustrate, I’ll start by defining a couple of errors:

enum MyFirstError : Error {
    case firstMinorMistake
    case firstMajorMistake
    case firstFatalMistake
}
enum MySecondError : Error {
    case secondMinorMistake(i:Int)
    case secondMajorMistake(s:String)
    case secondFatalMistake
}

Now here’s a do...catch construct designed to demonstrate some of the different ways we can catch different errors in different catch blocks:

do {
    // throw can happen here
} catch MyFirstError.firstMinorMistake {
    // catches MyFirstError.firstMinorMistake
} catch let err as MyFirstError {
    // catches all other cases of MyFirstError
} catch MySecondError.secondMinorMistake(let i) where i < 0 {
    // catches e.g. MySecondError.secondMinorMistake(i:-3)
} catch {
    // catches everything else
}

In a catch block with an accompanying pattern, it is up to you to capture in the pattern any desired information about the error. For example, if you want the error itself to travel as a variable into the catch block, you’ll need a binding in the pattern. A catch block whose pattern is only a binding catches any error under that name; for example, catch let mistake is a “mop-up” catch block that catches any error and calls the error object mistake. In a “mop-up” catch block with no accompanying pattern, the error object arrives into the block automatically as a variable called error.

Thus, let’s look again at the previous example, but this time we’ll note whether and how the error object arrives into each catch block:

do {
    // throw can happen here
} catch MyFirstError.firstMinorMistake {
    // no error object, but we know it's MyFirstError.firstMinorMistake
} catch let err as MyFirstError {
    // MyFirstError arrives as err
} catch MySecondError.secondMinorMistake(let i) where i < 0 {
    // only i arrives, but we know it's MySecondError.secondMinorMistake
} catch {
    // error object arrives as error
}

However, as I said earlier, there’s something else that can happen to a thrown error; instead of being caught directly, it can percolate up the calling chain, leaving the current function and arriving at the point where this function was called. In this situation, the error won’t be caught here, at the point of throwing; it needs to be caught further up the calling chain. Moreover, suppose a do...catch construct lacks a “mop-up” catch block. Then a throw inside the do block might not be caught here, and again, the error will percolate up the calling chain, and needs to be caught further up the calling chain.

We therefore need a way to say to the compiler: “Look, I understand that it looks like this throw is not happening in a context where it can be caught, but that’s only because you’re not looking far enough up the calling chain. If you do look far enough, you’ll see that a throw at this point is eventually caught.” That way is the throws keyword.

If you mark a function with the throws keyword, then its entire body becomes a legal place for throwing. The syntax for declaring a throws function is that the keyword throws appears immediately after the parameter list (and before the arrow operator, if there is one) in the function’s declaration. For example:

enum NotLongEnough : Error {
    case iSaidLongIMeantLong
}
func giveMeALongString(_ s:String) throws {
    if s.characters.count < 5 {
        throw NotLongEnough.iSaidLongIMeantLong
    }
    print("thanks for the string")
}

The addition of throws to a function declaration creates a distinct function type. The type of giveMeALongString is not (String) -> (), but rather (String) throws -> (). If a function receives as parameter a function that can throw, that parameter’s type needs to be specified accordingly:

func receiveThrower(_ f:(String) throws -> ()) {
    // ...
}

That function can now be called with giveMeALongString as argument:

func callReceiveThrower() {
    receiveThrower(giveMeALongString)
}

An anonymous function, if necessary, can include the keyword throws in its in line, in the same place where it would appear in a normal function declaration. But this is not necessary if, as is usually the case, the anonymous function’s type is known by inference:

func receiveThrower(_ f:(String) throws -> ()) {
    // ...
}
func callReceiveThrower() {
    receiveThrower {
        s in // can say "s throws in", but not required
        if s.characters.count < 5 {
            throw NotLongEnough.iSaidLongIMeantLong
        }
        print("thanks for the string")
    }
}

Swift also imposes a requirement on the caller of a throws function: the caller must precede the call with the keyword try. This keyword acknowledges, to the programmer and to the compiler, that this function can throw. But since this function can throw, there is a further requirement: this call must take place where throwing is legal! A function called with try can throw, so saying try is just like saying throw: you must say it either in the do block of a do...catch construct or in the body of a throws function.

So, for example:

func stringTest() {
    do {
        try giveMeALongString("is this long enough for you?")
    } catch {
        print("I guess it wasn't long enough: \(error)")
    }
}

But Swift also provides a clever shorthand. If you are very sure that a throws function will in fact not throw, then you can call it with the keyword try! instead of try. This relieves you of all further responsibility: you can say try! anywhere, without catching the possible throw. But be warned: if you’re wrong, and this function does throw when your program runs, your program can crash at that moment, because you have allowed an error to percolate, uncaught, all the way up to the top of the calling chain.

Thus, this is legal but dangerous; we are calling a throws function not in a do...catch block and not in another throws function, and telling the compiler to trust us and let us do it:

func stringTest() {
    try! giveMeALongString("okay")
}

In between try and try! is try?. This has the advantage that, like try!, you can use it anywhere; but, like a do...catch construct, it catches the throw if there is one, without crashing. If there’s a throw, you don’t receive any error information, as you would with a catch block; but try? tells you if there was a throw, by returning nil. Thus, try? is useful particularly in situations where its expression returns a value. If there’s a throw, it returns nil. If there’s no throw, it wraps the returned value in an Optional. Commonly, you’ll unwrap that Optional safely in the same line with a conditional binding. I’ll give an example in a moment.

Even if your own code never uses the keyword throw explicitly, you’re still very likely, in real life, to call Cocoa methods that are marked with throws. Therefore, you need to know how Swift’s error mechanism relates to Cocoa and Objective-C. Recall that an Objective-C method can return only one value (there are no tuples). So if a Cocoa method that returns a value has a failure and wants to hand back an NSError, how can it do it? The answer is that such a method will return nil to indicate failure, and will also take an NSError** parameter as a way of communicating an error to the caller in addition to the method result; the NSError** parameter is similar to a Swift inout parameter.

For example, NSString has an initializer declared in Objective-C like this:

- (instancetype)initWithContentsOfFile:(NSString *)path
                              encoding:(NSStringEncoding)enc
                                 error:(NSError **)error;

Objective-C code that calls that initializer must test to see whether the resulting NSString is in fact nil, and can examine the resulting error if it is:

NSError* err;
NSString* s =
    [[NSString alloc] initWithContentsOfFile:f
                                    encoding:NSUTF8StringEncoding
                                       error:&err];
if (s == nil) {
    NSLog(@"%@", err);
}

As you can see, the whole procedure is a lot like using a Swift inout parameter. An NSError variable must be prepared beforehand, and its address must be passed as the error: argument. Then we have to test the result for nil explicitly, to see whether the initialization succeeded. This is an annoyingly elaborate but necessary dance in Objective-C, and in Swift, prior to Swift 2.0, the dance was effectively the same.

In modern Swift, however, there’s a different dance — a much simpler, more pleasant one. Such an Objective-C method is automatically recast to take advantage of the error mechanism. The error: parameter is removed from the Swift translation of the declaration, and is replaced by a throws marker:

init(contentsOfFile path: String, encoding enc: String.Encoding) throws

Thus there is no need to declare an NSError variable beforehand, and no need to receive the NSError by indirection. Instead, you just call the method, within the controlled conditions dictated by Swift. And what are those conditions? One way is to say try, in a place where throwing is legal. The result in that case can never be nil; it’s a String, plain and simple, because if the initialization fails, the call will throw and no result will arrive at all. Here’s an example (the encoding: parameter is optional, and defaults to .utf8):

do {
    let f = // path to some file, maybe
    let s = try String(contentsOfFile: f)
    // ... if successful, do something with s ...
} catch {
    print(error.localizedDescription)
}

Alternatively, you’re very sure the initialization won’t fail, you can skip the do...catch construct and use try! instead; again, the result can never be nil, so it’s just a String:

let f = // path to some file, maybe
let s = try! String(contentsOfFile: f)

Finally, you can skip the do...catch construct and still proceed safely by using try?, in which case the value returned is an Optional wrapping a String, which you can test for nil to learn whether the initialization succeeded. You’ll probably unwrap the Optional safely at the same point where you make the call, like this:

let f = // path to some file, maybe
if let s = try? String(contentsOfFile: f) {
    // ...
}

Objective-C NSError and Swift Error are bridged to one another. Thus, in a catch block a moment ago, I examined the error variable using an NSError property. Moreover, you can catch the specific NSError by its name. The name you’ll use is the NSError domain, and optionally (with dot-notation) the Cocoa name of its code.

For example, let’s say we call init(contentsOfFile:) and we want specifically to catch the error thrown when there is no such file. This NSError’s domain, according to Cocoa, is "NSCocoaErrorDomain"; Swift sees that as CocoaError. Its code is 260, for which Cocoa provides the name NSFileReadNoSuchFileError (I found that out by looking in the FoundationErrors.h header file in Objective-C); Swift sees that as .fileReadNoSuchFile. Thus we can catch this specific error under the name CocoaError.fileReadNoSuchFile, like this:

do {
    let f = // path to some file, maybe
    let s = try String(contentsOfFile: f)
    // ... if successful, do something with s ...
} catch CocoaError.fileReadNoSuchFile {
    print("no such file")
} catch {
    print(error)
}

Objective-C sees a Swift error coherently as well. It receives a Swift error as an NSError whose domain is the name of the Swift object type. If the Swift object type is an enum, the NSError’s code is the index number of its case; otherwise, the code is 1.

Nested scopes

Sometimes, when you know that a local variable needs to exist only for a few lines of code, you might like to define an artificial scope — a custom nested scope, at the start of which you can introduce your local variable, and at the end of which that variable will be permitted to go out of scope, destroying its value automatically.

Swift, however, does not permit you to use bare curly braces to do this. Instead, use a bare do construct without a catch:

do {
    var myVar = "howdy"
    // ... use myVar here ...
}
// now myVar is out of scope and its value is destroyed

Defer

The purpose of the defer statement is to ensure that a certain block of code will be executed at the time the path of execution flows out of the current scope, no matter how.

A defer statement applies to the scope in which it appears, such as a function body, a while block, an if construct, a do block, and so on. Wherever you say defer, curly braces surround it somehow; the defer block will be executed when the path of execution leaves those curly braces. Leaving the curly braces can involve reaching the last line of code within the curly braces, or any of the forms of early exit described earlier in this section.

To see why this is useful, consider the following pair of commands:

UIApplication.shared.beginIgnoringInteractionEvents()
Stops all user touches from reaching any view of the application.
UIApplication.shared.endIgnoringInteractionEvents()
Restores the ability of user touches to reach views of the application.

It can be valuable to turn off user interactions at the start of some slightly time-consuming operation and then turn them back on after that operation, especially when, during the operation, the interface or the app’s logic will be in some state where the user’s tapping a button, say, could cause things to go awry. Thus, it is not uncommon for a method to be constructed like this:

func doSomethingTimeConsuming() {
    UIApplication.shared.beginIgnoringInteractionEvents()
    // ... do stuff ...
    UIApplication.shared.endIgnoringInteractionEvents()
}

All well and good — if we can guarantee that the only path of execution out of this function will be by way of that last line. But what if we need to return early from this function? Our code now looks like this:

func doSomethingTimeConsuming() {
    UIApplication.shared.beginIgnoringInteractionEvents()
    // ... do stuff ...
    if somethingHappened {
        return
    }
    // ... do more stuff ...
    UIApplication.shared.endIgnoringInteractionEvents()
}

Oops! We’ve just made a terrible mistake. By providing an additional path out of our doSomethingTimeConsuming function, we’ve created the possibility that our code might never encounter the call to endIgnoringInteractionEvents. We might leave our function by way of the return statement — and the user will then be left unable to interact with the interface. Obviously, we need to add another endIgnoring... call inside the if construct, just before the return statement. But as we continue to develop our code, we must remember, if we add further ways out of this function, to add yet another endIgnoring... call for each of them. This is madness!

The defer statement solves the problem. It lets us specify once what should happen when we leave this scope, no matter how. Our code now looks like this:

func doSomethingTimeConsuming() {
    defer {
        UIApplication.shared.endIgnoringInteractionEvents()
    }
    UIApplication.shared.beginIgnoringInteractionEvents()
    // ... do stuff ...
    if somethingHappened {
        return
    }
    // ... do more stuff ...
}

The endIgnoring... call in the defer block will be executed, not where it appears, but before the return statement, or before the last line of the method — whichever path of execution ends up leaving the function. The defer statement says: “Eventually, and as late as possible, be sure to execute this code.” We have thus ensured the necessary balance between turning off user interactions and turning them back on again. Most uses of the defer statement will probably come under this same rubric: you’ll use it to balance a command or restore a disturbed state.

Observe that in the preceding code, I placed the defer block very early in its surrounding scope, even though this caused the endIgnoring... call to precede visually the beginIgnoring... call that it balances. This placement is important because a defer block is itself, as a whole, executable code. If a defer block is not actually encountered by the path of execution before we exit from the surrounding scope, it won’t be executed. For this reason, always place your defer block as close to the start of its surrounding block as you can, to ensure that it will in fact be encountered.

Tip

If the current scope has multiple defer blocks pending, they will be called in the reverse of the order in which they were originally encountered. In effect, there is a defer stack; each successive defer statement, as it is encountered, pushes its code onto the top of the stack, and exiting the scope in which a defer statement appeared pops that code and executes it.

Aborting the whole program

Aborting the whole program is an extreme form of flow control; the program stops dead in its tracks. In effect, you have deliberately crashed your own program. This is an unusual thing to do, but it can be useful as a way of raising a very red flag: you don’t really want to abort, so if you do abort, things must be so bad that you’ve no choice.

One way to abort is by calling the global function fatalError. It takes a String parameter permitting you to provide a message to appear in the console. I’ve already given this example:

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

That code says, in effect, that execution should never reach this point. We have declared init(coder:) just because it is required, and we need to satisfy the compiler; but we have no real implementation of init(coder:), and we do not expect to be initialized this way. If we are initialized this way, something has gone very wrong, and we want to crash, because our program has a serious bug.

An initializer containing a fatalError call does not have to initialize any properties. This is because fatalError is declared as returning Never, which causes the compiler to abandon any contextual requirements. Similarly, a function that returns a value does not have to return any value if a fatalError call is encountered.

You can also abort conditionally by calling the assert function. Its first parameter is a condition — something that evaluates as a Bool. If the condition is false, we will abort; the second parameter is a String message to appear in the console if we do abort. The idea here is that you are making a bet (an assertion) that the condition is true — a bet that you feel so strongly about that if the condition is false, there’s a serious bug in your program and you want to crash so you can learn of this bug and fix it.

By default, assert works only when you’re developing your program. When your program is to be finalized and made public, you throw a different build switch, telling the compiler that assert should be ignored. In effect, the conditions in your assert calls are then disregarded; they are all seen as true. This means that you can safely leave assert calls in your code. By the time your program ships, of course, none of your assertions should be failing; any bugs that caused them to fail should already have been ironed out.

The disabling of assertions in shipping code is performed in an interesting way. The condition parameter is given an extra layer of indirection by declaring it as an @autoclosure function. This means that, even though the parameter is not in fact a function, the compiler will wrap it in a function; thus, the runtime needn’t call that function unless it has to. In shipping code, the runtime will not call that function. This mechanism averts expensive and unnecessary evaluation: an assert condition test may involve side effects, but the test won’t even be performed when assertions are turned off in your shipping program.

In addition, Swift provides the assertionFailure function. It’s like an assert that always fails — and, like an assert, it doesn’t fail in your shipping program where assertions are turned off. It’s a convenient synonym for assert(false), as a way of assuring yourself that your code never goes where it’s never supposed to go. By contrast, precondition and preconditionFailure are similar to assert and assertionFailure, except that they do fail even in a shipping program.

Guard

If the need for jumping might arise, you will probably want to test a condition that decides whether to jump. Swift provides a special syntax for this situation — the guard statement. In effect, a guard statement is an if statement where you must exit early in response to failure of the condition. Its form is shown in Example 5.6.

Example 5.6. The Swift guard statement

guard condition else {
    statements
    exit
}

A guard statement, as you can see, consists solely of a condition and an else block. The else block must jump out of the current scope, by any of the means that Swift provides, such as return, break, continue, throw, or fatalError — anything that guarantees to the compiler that, in case of failure of the condition, execution absolutely will not proceed within the block that contains the guard statement.

An elegant consequence of this architecture is that, because the guard statement guarantees an exit on failure of the condition, the compiler knows that the condition has succeeded after the guard statement if we do not exit. Thus, a conditional binding in the condition is in scope after the guard statement, without introducing a further nested scope. For example:

guard let s = optionalString else {return}
// s is now a String (not an Optional)

A series of guard statements, as I demonstrated earlier, can be a nice alternative to the “pyramid of doom”:

override func observeValue(forKeyPath keyPath: String?,
    of object: Any?, change: [NSKeyValueChangeKey : Any]?,
    context: UnsafeMutableRawPointer?) {
        guard keyPath == readyForDisplay else {return}
        guard let obj = object as? AVPlayerViewController else {return}
        guard let ok = change?[.newKey] as? Bool else {return}
        guard ok else {return}
        // ...
}

A guard statement will also come in handy in conjunction with try?. Let’s presume we can’t proceed unless String(contentsOfFile:) succeeds. Then we can rewrite our earlier example like this:

let f = // path to some file, maybe
guard let s = try? String(contentsOfFile: f)
    else {return}
// s is now a String (not an Optional)

There is also a guard case construct, forming the logical inverse of if case. To illustrate, we’ll use our Error enum once again:

guard case let .number(n) = err else {return}
// n is now the extracted number

guard case helps to solve an interesting problem. Suppose we have a function whose returned value we want to check in a guard statement:

guard howMany() > 10 else {return}

All well and good; but suppose also that in the next line we want to use the value returned from that function. We don’t want to call the function again; it might be time-consuming and it might have side effects. We want to capture the result of calling the function and pass that captured result on into the subsequent code. But we can’t do that with guard let, because that requires an Optional, and our function doesn’t return an Optional.

What should we do? Well, we could wrap the returned value from our function in an Optional just so we can unwrap it again:

guard let output = Optional(howMany()), output > 10 else {return}
// now output is in scope (not an Optional)

That happens to work, but it’s horrible. guard case to the rescue:

guard case let output = howMany(), output > 10 else {return}
// now output is in scope

Note that a guard statement’s conditional binding can’t use on the left side of the equal sign a name already declared in the same scope. This is illegal:

let s = // ... some Optional
guard let s = s else {return} // compile error

The reason is that guard let, unlike if let and while let, doesn’t declare the bound variable for a nested scope; it declares it for this scope. Thus, we can’t declare s here because s has already been declared in the same scope.

Operators

Swift operators such as + and > are not magically baked into the language. They are, in fact, functions; they are explicitly declared and implemented just like any other function. That is why, as I pointed out in Chapter 4, the term + can be passed as the second parameter in a reduce call; reduce expects a function taking two parameters and returning a value whose type matches that of the first parameter, and + is in fact the name of such a function. It also explains how Swift operators can be overloaded for different value types. You can use + with numbers, strings, or arrays — with a different meaning in each case — because two functions with the same name but different parameter types (different signatures) are two different functions; from the parameter types, Swift is able to determine which + function you are calling.

These facts are not merely an intriguing behind-the-scenes implementation detail. They have practical implications for you and your code. You are free to overload existing operators to apply to your object types. You can even invent new operators! In this section, we’ll do both.

First, we must talk about how operators are declared. Clearly there is some sort of syntactical hanky-panky (a technical computer science term), because you don’t call an operator function in the same way as a normal function. You don’t say +(1,2); you say 1+2. Even so, 1 and 2 in that second expression are the parameters to a + function call. How does Swift know that the + function uses this special syntax?

To see the answer, look in the Swift header:

infix operator + : AdditionPrecedence

That is an operator declaration. An operator declaration announces that this symbol is an operator, and tells how many parameters it has and what the usage syntax will be in relation to those parameters. The really important part is the stuff before the colon: the keyword operator, preceded by an operator type — here, infix — and followed by the name of the operator. The types are:

infix
This operator takes two parameters and appears between them.
prefix
This operator takes one parameter and appears before it.
postfix
This operator takes one parameter and appears after it.

The term after the colon in an operator declaration is the name of a precedence group. I’m not going to go into the details of how precedence groups are defined. The Swift header declares about a dozen of them, and you can easily see how those declarations work. You will probably have no need to declare a new precedence group; instead, you’ll just look for an operator similar to yours and copy its precedence group (or omit the colon and the precedence group from your declaration).

An operator is also a function, so you also need a function declaration stating the type of the parameters and the result type of the function. Again, the Swift header shows us an example:

func +(lhs: Int, rhs: Int) -> Int

That is one of many declarations for the + function in the Swift header. In particular, it is the declaration for when the parameters are both Int. In that situation, the result is itself an Int. (The local parameter names lhs and rhs, which don’t affect the special calling syntax, presumably stand for “left-hand side” and “right-hand side.”)

An operator declaration must appear at the top level of a file. The corresponding function declaration may appear either at the top level of a file or at the top level of a type declaration; in the latter case, it must be marked static. If the operator is a prefix or postfix operator, the function declaration must start with the word prefix or postfix; the default is infix and can be omitted.

We now know enough to override an operator to work with an object type of our own! As a simple example, imagine a Vial full of bacteria:

struct Vial {
    var numberOfBacteria : Int
    init(_ n:Int) {
        self.numberOfBacteria = n
    }
}

When two Vials are combined, you get a Vial with all the bacteria from both of them. So the way to add two Vials is to add their bacteria:

extension Vial {
    static func +(lhs:Vial, rhs:Vial) -> Vial {
        let total = lhs.numberOfBacteria + rhs.numberOfBacteria
        return Vial(total)
    }
}

And here’s code to test our new + operator override:

let v1 = Vial(500_000)
let v2 = Vial(400_000)
let v3 = v1 + v2
print(v3.numberOfBacteria) // 900000

In the case of a compound assignment operator, the first parameter is the thing being assigned to. Therefore, to implement such an operator, the first parameter must be declared inout. Let’s do that for our Vial class:

extension Vial {
    static func +=(lhs:inout Vial, rhs:Vial) {
        let total = lhs.numberOfBacteria + rhs.numberOfBacteria
        lhs.numberOfBacteria = total
    }
}

Here’s code to test our += override:

var v1 = Vial(500_000)
let v2 = Vial(400_000)
v1 += v2
print(v1.numberOfBacteria) // 900000

It might be useful also to override the equality comparison operator == for our Vial class. This satisfies the requirement for Vial to adopt the Equatable protocol, but of course it won’t actually adopt it unless we tell it to:

extension Vial : Equatable {
    static func ==(lhs:Vial, rhs:Vial) -> Bool {
        return lhs.numberOfBacteria == rhs.numberOfBacteria
    }
}

Now that Vial is an Equatable, it becomes a candidate for use with methods such as index(of:):

let v1 = Vial(500_000)
let v2 = Vial(400_000)
let arr = [v1,v2]
let ix = arr.index(of:v1) // Optional wrapping 0

What’s more, the complementary inequality operator != has sprung to life for Vials automatically! That’s because it’s already defined for any Equatable in terms of the == operator. By the same token, if we now override < for Vial and tell it to adopt Comparable, the other three comparison operators spring to life automatically.

Next, let’s invent a completely new operator. As an example, I’ll inject an operator into Int that raises one number to the power of another. As my operator symbol, I’ll use ^^ (I’d like to use ^ but it’s already in use for something else). For simplicity, I’ll omit error-checking for edge cases (such as exponents less than 1):

infix operator ^^
extension Int {
    static func ^^(lhs:Int, rhs:Int) -> Int {
        var result = lhs
        for _ in 1..<rhs {result *= lhs}
        return result
    }
}

That’s all it takes! Here’s some code to test it:

print(2^^2) // 4
print(2^^3) // 8
print(3^^3) // 27

Here’s another example. I’ve already illustrated the use of Range’s reversed method to allow iteration from a higher value to a lower one. That works, but I find the notation unpleasant. There’s an asymmetry with how you iterate up; the endpoints are in the wrong order, and you have to remember to surround a literal range with parentheses:

let r1 = 1..<10
let r2 = (1..<10).reversed()

Let’s define a custom operator that calls reversed() for us:

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedRandomAccessCollection<CountableRange<Bound>>
    where Bound : Comparable & Strideable, Bound.Stride : Integer {
        return (minimum..<maximum).reversed()
}

Now our expressions can be more symmetrical and compact:

let r1 = 1..<10
let r2 = 10>>>1

The Swift manual lists the special characters that can be used as part of a custom operator name:

/ = - + ! * % < > & | ^ ? ~

An operator name can also contain many other symbol characters (that is, characters that can’t be mistaken for some sort of alphanumeric) that are harder to type; see the manual for a formal list.

Privacy

Privacy (also known as access control) refers to the explicit modification of the normal scope rules. I gave an example in Chapter 1:

class Dog {
    var name = ""
    private var whatADogSays = "woof"
    func bark() {
        print(self.whatADogSays)
    }
}

The intention here is to limit how other objects can see the Dog property whatADogSays. It is a private property, intended primarily for the Dog class’s own internal use: a Dog can speak of self.whatADogSays, but other objects should not be aware that it even exists.

Swift 3 has five levels of privacy:

internal
The default rule is that declarations are internal, meaning that they are globally visible to all code in all files within the containing module. That is why Swift files within the same module can see one another’s top-level contents automatically, with no effort on your part. (That’s different from C and Objective-C, where files can’t see each other at all unless you explicitly show them to one another through include or import statements.)
fileprivate (narrower than internal)
A thing declared fileprivate is visible only within its containing file. For example, two object types declared in the same file can see one another’s members declared fileprivate, but code in other files cannot see those members.
private (even narrower than fileprivate)
A thing declared private is visible only within its containing curly braces. In effect, the visibility of an object type’s member declared private is limited to code within this class declaration. (A private declaration at the top level of a file is equivalent to fileprivate.)
public (wider than internal)
A thing declared public is visible even outside its containing module. Another module must first import this module before it can see anything at all. But once another module has imported this module, it still won’t be able to see anything in this module that hasn’t been explicitly declared public. If you don’t write any modules, you might never need to declare anything public. If you do write a module, you must declare something public, or your module is useless.
open (even wider than public)
If a class is declared open, code in another module can subclass it; it can’t do that if the class is declared merely public. If an open class member is declared open, code in another module that subclasses this class can override this member; it can’t do that without the open declaration.

Tip

fileprivate and open are new in Swift 3. Before Swift 3, private meant fileprivate, and public implied open.

Private and Fileprivate

Declaring something private restricts its visibility. In this way, you specify by inversion what the public API of this object is. Here’s an example from my own code:

class CancelableTimer: NSObject {
    private var q = DispatchQueue(label: "timer")
    private var timer : DispatchSourceTimer!
    private var firsttime = true
    private var once : Bool
    private var handler : () -> ()
    init(once:Bool, handler:@escaping ()->()) {
        // ...
    }
    func start(withInterval interval:Double) {
        // ...
    }
    func cancel() {
        // ...
    }
}

The initializer init(once:handler:) and the start(withInterval:) and cancel methods, which are not marked private, are this class’s public API. They say, “Please feel free to call me!” The properties, however, are all private; no other code can see them, either to get them or to set them. They are purely for the internal use of the methods of this class. They maintain state, but it is not a state that any other code needs to know about.

Why would you declare something fileprivate rather than private? One common reason has to do with extensions. The rules about private are very strict; the surrounding curly braces are an absolute barrier. Well, an extension to a class is outside the curly braces that define that class. Therefore, code in an extension to a class can’t see members of that class declared private! That is unlikely to be what you want, so you’ll have to declare those members fileprivate instead.

By the same token, privacy is not magically violated by the existence of a special object relationship. For example, even a subclass cannot see its superclass’s private members. (This comes as a surprise to those coming from a language with a protected privacy level.) You can work around this by declaring the class and its subclass in the same file and declaring those members fileprivate instead of private.

It may be that on some occasions you will want to draw a distinction between the privacy of a variable regarding setting and its privacy regarding getting. To draw this distinction, place the word set in parentheses after its own privacy declaration. Thus, private(set) var myVar or fileprivate(set) var myVar means that the setting of this variable is restricted, but says nothing about the getting of this variable, which is left at the default. Similarly, you can say public private(set) var myVar to make getting this variable public, while setting this variable is kept private. (You can use this same syntax with a subscript function.)

Public and Open

If you write a module, you’ll need to specify at least some object type declaration as public, or code that imports your module won’t be able to see that type. Other declarations that are not declared public are internal, meaning that they are private to the module. Thus, judicious use of public declarations configures the public API of your module.

For example, in my Zotz app, which is a card game, the object types for creating and portraying cards and for combining them into a deck are bundled into a framework called ZotzDeck. Many of these types, such as Card and Deck, are declared public. Many utility object types, however, are not; the classes within the ZotzDeck module can see and use them, but code outside the module doesn’t need to be aware of them at all.

The members of a public object type are not, themselves, automatically public. If you want a method to be public, you have to declare it public. This is an excellent default behavior, because it means that these members are not shared outside the module unless you want them to be. (As Apple puts it, you must “opt in to publishing” object members.)

For example, in my ZotzDeck module, the Card class is declared public but its initializer is not. Why not? Because it doesn’t need to be. The way you (meaning the importer of the ZotzDeck module) get cards is by initializing a Deck; the initializer for Deck is declared public, so you can do that. There is never any reason to make a card independently of a Deck, and thanks to the privacy rules, you can’t.

Tip

If the only initializer for a public type is implicit, code in another module can’t see it and thus cannot create an instance of this type. If you want other code to be able to create an instance of this type, you must declare the initializer explicitly and declare it public.

New in Swift 3, a further access level open draws a further distinction. It is applicable only to classes and to members of open classes. A public class can’t be subclassed in another module that can see this class; an open class can. A public member of an open class that has been subclassed in another module can’t be overridden in that subclass; an open member can. (Prior to Swift 3, public also meant open; Swift 3 thus draws a distinction that provides a form of protection that was previously impossible.)

Privacy Rules

It took time for Apple to add access control to Swift in the early months of the language’s release, mostly because the compiler had to be taught an extensive set of rules for ensuring that the privacy level of related things is coherent. For example:

  • A variable can’t be public if its type is private, because other code wouldn’t be able to use such a variable.
  • A subclass can’t be public unless the superclass is public.
  • A subclass can change an overridden member’s access level, but it cannot even see its superclass’s private members unless they are declared in the same file together.

And so on. I could proceed to list all the rules, but I won’t. There is no need for me to enunciate them formally. They are spelled out in great detail in the Swift manual, which you can consult if you need to. In general, you probably won’t need to; the privacy rules make intuitive sense, and you can rely on the compiler to help you with useful error messages if you violate one.

Introspection

Swift provides limited ability to introspect an object, letting an object display the names and values of its properties. This feature is intended for debugging, not for use in your program’s logic. For example, you can use it to modify the way your object is displayed in the Xcode Debug pane.

To introspect an object, use it as the reflecting: parameter when you instantiate a Mirror. The Mirror’s children will then be name–value tuples describing the original object’s properties. Here, for example, is a Dog class with a description property that takes advantage of introspection. Instead of hard-coding a list of the class’s instance properties, we introspect the instance to obtain the names and values of the properties. This means that we can later add more properties without having to modify our description implementation:

struct Dog : CustomStringConvertible {
    var name = "Fido"
    var license = 1
    var description : String {
        var desc = "Dog ("
        let mirror = Mirror(reflecting:self)
        for (k,v) in mirror.children {
            desc.append("\(k!): \(v), ")
        }
        let c = desc.characters.count
        return String(desc.characters.prefix(c-2)) + ")"
    }
}

If we now instantiate Dog and pass that instance to print, this is what we see in the console:

Dog (name: Fido, license: 1)

Tip

If your object type adopts both the CustomStringConvertible protocol (description property) and the CustomDebugStringConvertible protocol (debugDescription property), the description will be preferred, but you can output the debugDescription with the debugPrint function.

By adopting the CustomReflectable protocol, we can take charge of what a Mirror’s children are. To do so, we supply the customMirror property to return our own custom Mirror object whose children property we have configured as a collection of name–value tuples.

In this (silly) example, we implement customMirror to supply altered names for our properties:

struct Dog : CustomReflectable {
    var name = "Fido"
    var license = 1
    var customMirror: Mirror {
        let children : [Mirror.Child] = [
            ("ineffable name", self.name),
            ("license to kill", self.license)
        ]
        let m = Mirror(self, children:children)
        return m
    }
}

The outcome is that when we po a Dog instance in the Xcode Debug pane console, our custom property names are displayed:

- ineffable name : "Fido"
- license to kill : 1

Memory Management

Swift memory management is handled automatically, and you will usually be unaware of it. Objects come into existence when they are instantiated and go out of existence as soon as they are no longer needed. Memory management of reference type objects, however, is quite tricky under the hood. Even for the Swift user, things can occasionally go wrong in this regard. (Value types do not require the sort of complex memory management that reference types do, so no memory management issues can arise for them.)

Trouble typically arises when two class instances have references to one another. When that’s the case, you can have a retain cycle which will result in a memory leak, meaning that the two instances never go out of existence. Some computer languages solve this sort of problem with a periodic “garbage collection” phase that detects retain cycles and cleans them up, but Swift doesn’t do that; you have to fend off retain cycles manually.

One way to test for and observe a memory leak is to implement a class’s deinit. This method is called when the instance goes out of existence. If the instance never goes out of existence, deinit is never called. That’s a bad sign, if you were expecting that the instance should go out of existence.

Here’s an example. First, I’ll make two class instances and watch them go out of existence:

func testRetainCycle() {
    class Dog {
        deinit {
            print("farewell from Dog")
        }
    }
    class Cat {
        deinit {
            print("farewell from Cat")
        }
    }
    let d = Dog()
    let c = Cat()
}
testRetainCycle() // farewell from Cat, farewell from Dog

When we run that code, both “farewell” messages appear in the console. We created a Dog instance and a Cat instance, but the only references to them are automatic (local) variables inside the testRetainCycle function. When execution of that function’s body comes to an end, all automatic variables are destroyed; that is what it means to be an automatic variable. There are no other references to our Dog and Cat instances that might make them persist, and so they are destroyed in good order.

Now I’ll change that code by giving the Dog and Cat objects references to each other:

func testRetainCycle() {
    class Dog {
        var cat : Cat?
        deinit {
            print("farewell from Dog")
        }
    }
    class Cat {
        var dog : Dog?
        deinit {
            print("farewell from Cat")
        }
    }
    let d = Dog()
    let c = Cat()
    d.cat = c // create a...
    c.dog = d // ...retain cycle
}
testRetainCycle() // nothing in console

When we run that code, neither “farewell” message appears in the console. The Dog and Cat objects have references to one another. Those are persisting references (also called strong references). A persisting reference sees to it that, for example, as long as our Dog has a reference to a particular Cat, that Cat will not be destroyed. That’s a good thing, and is a fundamental principle of sensible memory management. The bad thing is that the Dog and the Cat have persisting references to one another. That’s a retain cycle! Neither the Dog instance nor the Cat instance can be destroyed, because neither of them can “go first” — it’s like Alphonse and Gaston who can never get through the door because each requires the other to precede him. The Dog can’t be destroyed first because the Cat has a persisting reference to him, and the Cat can’t be destroyed first because the Dog has a persisting reference to him.

These objects are therefore now leaking. Our code is over; both d and c are gone. There are no further references to either of these objects; neither object can ever be referred to again. No code can mention them; no code can reach them. But they live on, floating, useless, and taking up memory.

Weak References

One solution to a retain cycle is to mark the problematic reference as weak. This means that the reference is not a persisting reference. It is a weak reference. The object referred to can now go out of existence even while the referrer continues to exist. Of course, this presents a terrible danger, because now the object referred to may be destroyed behind the referrer’s back. But Swift has a solution for that, too: only an Optional reference can be marked as weak. That way, if the object referred to is destroyed behind the referrer’s back, the referrer will see something coherent, namely nil. Also, the reference must be a var reference, precisely because it can change spontaneously to nil.

Thus, this code breaks the retain cycle and prevents the memory leak:

func testRetainCycle() {
    class Dog {
        weak var cat : Cat?
        deinit {
            print("farewell from Dog")
        }
    }
    class Cat {
        weak var dog : Dog?
        deinit {
            print("farewell from Cat")
        }
    }
    let d = Dog()
    let c = Cat()
    d.cat = c
    c.dog = d
}
testRetainCycle() // farewell from Cat, farewell from Dog

I’ve gone overboard in that code. To break the retain cycle, there’s no need to make both Dog’s cat and Cat’s dog weak references; making just one of the two a weak reference is sufficient to break the cycle. That, in fact, is the usual solution when a retain cycle threatens. One of the pair will be more of an “owner” than the other; the one that is not the “owner” will have a weak reference to its “owner.”

Although, as I mentioned earlier, value types are not subject to the same memory management issues as reference types, a value type can still be involved in a retain cycle with a class instance. In my retain cycle example, if Dog is a class and Cat is a struct, we still get a retain cycle. The solution is the same: make Cat’s dog a weak reference. (You can’t make Dog’s cat a weak reference if Cat is a struct; only a reference to a class type can be declared weak.)

Do not use weak references unless you have to! Memory management is not to be toyed with lightly. Nevertheless, there are real-life situations in which weak references are the right thing to do, even when no retain cycle appears to threaten. For example, a view controller’s references to subviews of its own view are usually weak, because the view itself already has persisting references to those subviews, and we would not typically want those subviews to persist in the absence of the view itself:

class HelpViewController: UIViewController {
    weak var wv : UIWebView?
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let wv = UIWebView(frame:self.view.bounds)
        // ... further configuration of wv here ...
        self.view.addSubview(wv)
        self.wv = wv
    }
    // ...
}

In that code, self.view.addSubview(wv) causes the UIWebView wv to persist; our own reference to it, self.wv, can thus be weak.

Unowned References

There’s another Swift solution for retain cycles. Instead of marking a reference as weak, you can mark it as unowned. This approach is useful in special cases where one object absolutely cannot exist without a reference to another, but where this reference need not be a persisting reference.

For example, let’s pretend that a Boy may or may not have a Dog, but every Dog must have a Boy — and so I’ll give Dog an init(boy:) initializer. The Dog needs a reference to its Boy, and the Boy needs a reference to his Dog if he has one; that’s potentially a retain cycle:

func testUnowned() {
    class Boy {
        var dog : Dog?
        deinit {
            print("farewell from Boy")
        }
    }
    class Dog {
        let boy : Boy
        init(boy:Boy) { self.boy = boy }
        deinit {
            print("farewell from Dog")
        }
    }
    let b = Boy()
    let d = Dog(boy: b)
    b.dog = d
}
testUnowned() // nothing in console

We can solve this by declaring Dog’s boy property unowned:

func testUnowned() {
    class Boy {
        var dog : Dog?
        deinit {
            print("farewell from Boy")
        }
    }
    class Dog {
        unowned let boy : Boy // *
        init(boy:Boy) { self.boy = boy }
        deinit {
            print("farewell from Dog")
        }
    }
    let b = Boy()
    let d = Dog(boy: b)
    b.dog = d
}
testUnowned() // farewell from Boy, farewell from Dog

An advantage of an unowned reference is that it doesn’t have to be an Optional — in fact, it cannot be an Optional — and it can be a constant (let). But an unowned reference is also dangerous, because the object referred to can go out of existence behind the referrer’s back, and an attempt to use that reference will cause a crash, as I can demonstrate by this rather forced code:

var b = Optional(Boy())
let d = Dog(boy: b!)
b = nil // destroy the Boy behind the Dog's back
print(d.boy) // crash

Thus, you should use unowned only if you are absolutely certain that the object referred to will outlive the referrer.

Weak and Unowned References in Anonymous Functions

A subtle variant of a retain cycle arises when an instance property’s value is a function referring to the instance:

class FunctionHolder {
    var function : ((Void) -> Void)?
    deinit {
        print("farewell from FunctionHolder")
    }
}
func testFunctionHolder() {
    let fh = FunctionHolder()
    fh.function = {
        print(fh)
    }
}
testFunctionHolder() // nothing in console

Oops! I’ve created a retain cycle, by referring, inside the anonymous function, to the object that is holding a reference to it. Because functions are closures, the FunctionHolder instance fh, declared outside the anonymous function, is captured by the anonymous function as a persisting reference. But the function property of this FunctionHolder contains this anonymous function, and that’s a persisting reference too. So that’s a retain cycle: the FunctionHolder persistently refers to the function, which persistently refers to the FunctionHolder.

In this situation, I cannot break the retain cycle by declaring the function property as weak or unowned. Only a reference to a class type can be declared weak or unowned, and a function is not a class. Thus, I must declare the captured value fh inside the anonymous function as weak or unowned instead.

Swift provides an ingenious syntax for doing that. At the very start of the anonymous function body, where the in line would go (and before the in line if there is one), you put square brackets containing a comma-separated list of any problematic references that will be captured from the surrounding environment, each reference preceded by weak or unowned. This list is called a capture list. If you have a capture list, you must follow it by the keyword in if you are not already including the keyword in for other reasons:

class FunctionHolder {
    var function : ((Void) -> Void)?
    deinit {
        print("farewell from FunctionHolder")
    }
}
func testFunctionHolder() {
    let fh = FunctionHolder()
    fh.function = {
        [weak fh] in // *
        print(fh)
    }
}
testFunctionHolder() // farewell from FunctionHolder

This syntax solves the problem. But marking a reference as weak in a capture list has a mild side effect that you will need to be aware of: such a reference passes into the anonymous function as an Optional. This is good, because it means that if the object referred to goes out of existence behind our back, the value of the Optional is nil. But of course you must also adjust your code accordingly, unwrapping the Optional as needed in order to use it. The usual technique is to perform the weak–strong dance: you unwrap the Optional once, right at the start of the function, in a conditional binding:

class FunctionHolder {
    var function : ((Void) -> Void)?
    deinit {
        print("farewell from FunctionHolder")
    }
}
func testFunctionHolder() {
    let fh = FunctionHolder()
    fh.function = {   // here comes the weak–strong dance...
        [weak fh] in  // weak
        guard let fh = fh else { return }
        print(fh)     // strong
    }
}
testFunctionHolder() // farewell from FunctionHolder

The conditional binding let fh = fh accomplishes two goals. First, it unwraps the Optional version of fh that arrived into the anonymous function. Second, it declares another fh that is a normal (strong) reference. So if the unwrapping succeeds, this new fh will persist for the rest of this scope.

In that particular example, there is no way on earth that this FunctionHolder instance, fh, can go out of existence while the anonymous function lives on. There are no other references to the anonymous function; it persists only as a property of fh. Therefore I can avoid some behind-the-scenes bookkeeping overhead, as well as the weak–strong dance, by declaring fh as unowned in my capture list instead.

In real life, my own most frequent use of unowned is precisely in this context. Very often, the reference marked as unowned in the capture list will be self. Here’s an example from my own code:

class MyDropBounceAndRollBehavior : UIDynamicBehavior {
    let v : UIView
    init(view v:UIView) {
        self.v = v
        super.init()
    }
    override func willMove(to anim: UIDynamicAnimator?) {
        guard let anim = anim else { return }
        let sup = self.v.superview!
        let grav = UIGravityBehavior()
        grav.action = {
            [unowned self] in
            let items = anim.items(in:sup.bounds) as! [UIView]
            if items.index(of:self.v) == nil {
                anim.removeBehavior(self)
                self.v.removeFromSuperview()
            }
        }
        self.addChildBehavior(grav)
        grav.addItem(self.v)
        // ...
    }
    // ...
}

There’s a potential (and rather elaborate) retain cycle here: self.addChildBehavior(grav) causes a persistent reference to grav, grav has a persistent reference to grav.action, and the anonymous function assigned to grav.action refers to self. To break the retain cycle, I declare the reference to self as unowned in the anonymous function’s capture list.

Tip

Don’t panic! Beginners have a tendency to backstop all their anonymous functions with [weak self]. That’s unnecessary and wrong. Only a retained function can raise even the possibility of a retain cycle. Merely passing a function does not introduce such a possibility, especially if the function being passed will be called immediately. Always confirm that you actually have a retain cycle before concerning yourself with how to prevent a retain cycle.

Memory Management of Protocol-Typed References

Only a reference to an instance of a class type can be declared weak or unowned. A reference to an instance of a struct or enum type cannot be so declared, because its memory management doesn’t work the same way (and is not subject to retain cycles).

A reference that is declared as a protocol type, therefore, has a problem. A protocol might be adopted by a struct or an enum. Therefore you cannot wantonly declare such a reference weak or unowned. You can only declare a protocol-typed reference weak or unowned if it is a class protocol — that is, if it is marked with @objc or class.

In this code, SecondViewControllerDelegate is a protocol that I’ve declared. This code won’t compile unless SecondViewControllerDelegate is declared as a class protocol:

class SecondViewController : UIViewController {
    weak var delegate : SecondViewControllerDelegate?
    // ...
}

Here’s the actual declaration of SecondViewControllerDelegate; it is declared as a class protocol, and that’s why the preceding code is legal:

protocol SecondViewControllerDelegate : class {
    func accept(data:Any!)
}

A protocol declared in Objective-C is implicitly marked as @objc and is a class protocol. Thus, this declaration from my real-life code is legal:

weak var delegate : WKScriptMessageHandler?

WKScriptMessageHandler is a protocol declared by Cocoa (in particular, by the Web Kit framework). Thus, it is implicitly marked @objc; only a class can adopt WKScriptMessageHandler, and so the compiler is satisfied that the delegate variable will be an instance of a class, and thus the reference can be treated as weak.