Swift Chapter 4 2018-12-19T13:06:55+00:00

SWIFT CHAPTER 4

Topics:( Control Flow(loops),Conditional Statements,Control Transfer Statements,Labeled Statements,Functions, Function Types,Nested Functions,Closures)

Control Flow

Swift provides a variety of control flow statements. These include while loops to perform a task multiple times; if, guard, and switch statements to execute different branches of code based on certain conditions; and statements such as break and continue to transfer the flow of execution to another point in your code.Swift also provides a forin loop that makes it easy to iterate over arrays, dictionaries, ranges, strings, and other sequences.

Swift’s switch statement is considerably more powerful than its counterpart in many C-like languages. Cases can match many different patterns, including interval matches, tuples, and casts to a specific type. Matched values in a switch case can be bound to temporary constants or variables for use within the case’s body, and complex matching conditions can be expressed with a where clause for each case.

For-In Loops

You use the forin loop to iterate over a sequence, such as items in an array, ranges of numbers, or characters in a string.This example uses a forin loop to iterate over the items in an array:

let names = [“Anna”, “Alex”, “Brian”, “Jack”]

for name in names {

    print(“Hello, \(name)!”)

}

// Hello, Anna!

// Hello, Alex!

// Hello, Brian!

// Hello, Jack!

You can also iterate over a dictionary to access its key-value pairs. Each item in the dictionary is returned as a (key, value) tuple when the dictionary is iterated, and you can decompose the (key, value) tuple’s members as explicitly named constants for use within the body of the forin loop. In the code example below, the dictionary’s keys are decomposed into a constant called animalName, and the dictionary’s values are decomposed into a constant called legCount.

let numberOfLegs = [“spider”: 8, “ant”: 6, “cat”: 4]

for (animalName, legCount) in numberOfLegs {

    print(\(animalName)s have \(legCount) legs”)

}

// ants have 6 legs

// spiders have 8 legs

// cats have 4 legs

The contents of a Dictionary are inherently unordered, and iterating over them does not guarantee the order in which they will be retrieved. In particular, the order you insert items into a Dictionary doesn’t define the order they are iterated.You can also use forin loops with numeric ranges. This example prints the first few entries in a five-times table:

for index in 1…5 {

    print(\(index) times 5 is \(index * 5))

}

// 1 times 5 is 5

// 2 times 5 is 10

// 3 times 5 is 15

// 4 times 5 is 20

// 5 times 5 is 25

The sequence being iterated over is a range of numbers from 1 to 5, inclusive, as indicated by the use of the closed range operator (). The value of index is set to the first number in the range (1), and the statements inside the loop are executed. After the statement is executed, the value of index is updated to contain the second value in the range (2), and the print(_:separator:terminator:) function is called again. This process continues until the end of the range is reached.

In the example above, index is a constant whose value is automatically set at the start of each iteration of the loop. As such, index does not have to be declared before it is used. It is implicitly declared simply by its inclusion in the loop declaration, without the need for a let declaration keyword.If you don’t need each value from a sequence, you can ignore the values by using an underscore in place of a variable name.

let base = 3

let power = 10

var answer = 1

for _ in 1power {

    answer *= base

}

print(\(base) to the power of \(power) is \(answer))

// Prints “3 to the power of 10 is 59049”

The example above calculates the value of one number to the power of another (in this case, 3 to the power of 10). It multiplies a starting value of 1 (that is, 3 to the power of 0) by 3, ten times, using a closed range that starts with 1 and ends with 10. For this calculation, the individual counter values each time through the loop are unnecessary—the code simply executes the loop the correct number of times. The underscore character (_) used in place of a loop variable causes the individual values to be ignored and does not provide access to the current value during each iteration of the loop.

In some situations, you might not want to use closed ranges, which include both endpoints. Consider drawing the tick marks for every minute on a watch face. You want to draw 60 tick marks, starting with the 0 minute. Use the half-open range operator (..<) to include the lower bound but not the upper bound.

let minutes = 60

for tickMark in 0..<minutes {

    // render the tick mark each minute (60 times)

}

Some users might want fewer tick marks in their UI. They could prefer one mark every 5 minutes instead. Use the stride(from:to:by:) function to skip the unwanted marks.

let minuteInterval = 5

for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {

    // render the tick mark every 5 minutes (0, 5, 10, 15 … 45, 50, 55)

}

Closed ranges are also available, by using stride(from:through:by:) instead:

let hours = 12

let hourInterval = 3

for tickMark in stride(from: 3, through: hours, by: hourInterval) {

    // render the tick mark every 3 hours (3, 6, 9, 12)

}

While Loops

A while loop performs a set of statements until a condition becomes false. These kinds of loops are best used when the number of iterations is not known before the first iteration begins. Swift provides two kinds of while loops:while evaluates its condition at the start of each pass through the loop.repeatwhile evaluates its condition at the end of each pass through the loop.

While

A while loop starts by evaluating a single condition. If the condition is true, a set of statements is repeated until the condition becomes false.Here’s the general form of a while loop:

while condition {

    statements

}

This example plays a simple game of Snakes and Ladders:

   

The rules of the game are as follows:

The board has 25 squares, and the aim is to land on or beyond square 25.

The player’s starting square is “square zero”, which is just off the bottom-left corner of the board.

Each turn, you roll a six-sided dice and move by that number of squares, following the horizontal path indicated by the dotted arrow above.

If your turn ends at the bottom of a ladder, you move up that ladder.

If your turn ends at the head of a snake, you move down that snake.

The game board is represented by an array of Int values. Its size is based on a constant called finalSquare, which is used to initialize the array and also to check for a win condition later in the example. Because the players start off the board, on “square zero”, the board is initialized with 26 zero Int values, not 25.

let finalSquare = 25

var board = [Int](repeating: 0, count: finalSquare + 1)

Some squares are then set to have more specific values for the snakes and ladders. Squares with a ladder base have a positive number to move you up the board, whereas squares with a snake head have a negative number to move you back down the board.

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02

board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

Square 3 contains the bottom of a ladder that moves you up to square 11. To represent this, board[03] is equal to +08, which is equivalent to an integer value of 8 (the difference between 3 and 11). To align the values and statements, the unary plus operator (+i) is explicitly used with the unary minus operator (-i) and numbers lower than 10 are padded with zeros. (Neither stylistic technique is strictly necessary, but they lead to neater code.)

var square = 0

var diceRoll = 0

while square < finalSquare {

    // roll the dice

    diceRoll += 1

    if diceRoll == 7 { diceRoll = 1 }

    // move by the rolled amount

    square += diceRoll

    if square < board.count {

        // if we’re still on the board, move up or down for a snake or a ladder

        square += board[square]

    }

}

print(“Game over!”

The example above uses a very simple approach to dice rolling. Instead of generating a random number, it starts with a diceRoll value of 0. Each time through the while loop, diceRoll is incremented by one and is then checked to see whether it has become too large. Whenever this return value equals 7, the dice roll has become too large and is reset to a value of 1. The result is a sequence of diceRoll values that is always 1, 2, 3, 4, 5, 6, 1, 2 and so on.

After rolling the dice, the player moves forward by diceRoll squares. It’s possible that the dice roll may have moved the player beyond square 25, in which case the game is over. To cope with this scenario, the code checks that square is less than the board array’s count property. If square is valid, the value stored in board[square] is added to the current square value to move the player up or down any ladders or snakes.If this check is not performed, board[square] might try to access a value outside the bounds of the board array, which would trigger a runtime error.

The current while loop execution then ends, and the loop’s condition is checked to see if the loop should be executed again. If the player has moved on or beyond square number 25, the loop’s condition evaluates to false and the game ends.A while loop is appropriate in this case, because the length of the game is not clear at the start of the while loop. Instead, the loop is executed until a particular condition is satisfied.

Repeat-While

The other variation of the while loop, known as the repeatwhile loop, performs a single pass through the loop block first, before considering the loop’s condition. It then continues to repeat the loop until the condition is false.The repeatwhile loop in Swift is analogous to a dowhile loop in other languages.

Here’s the general form of a repeatwhile loop:

repeat {

    statements

} while condition

Here’s the Snakes and Ladders example again, written as a repeatwhile loop rather than a while loop. The values of finalSquare, board, square, and diceRoll are initialized in exactly the same way as with a while loop.

let finalSquare = 25

var board = [Int](repeating: 0, count: finalSquare + 1)

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02

board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

var square = 0

var diceRoll = 0

In this version of the game, the first action in the loop is to check for a ladder or a snake. No ladder on the board takes the player straight to square 25, and so it isn’t possible to win the game by moving up a ladder. Therefore, it’s safe to check for a snake or a ladder as the first action in the loop.

At the start of the game, the player is on “square zero”. board[0] always equals 0 and has no effect.

repeat {

    // move up or down for a snake or ladder

    square += board[square]

    // roll the dice

    diceRoll += 1

    if diceRoll == 7 { diceRoll = 1 }

    // move by the rolled amount

    square += diceRoll

} while square < finalSquare

print(“Game over!”

After the code checks for snakes and ladders, the dice is rolled and the player is moved forward by diceRoll squares. The current loop execution then ends.

The loop’s condition (while square < finalSquare) is the same as before, but this time it’s not evaluated until the end of the first run through the loop. The structure of the repeatwhile loop is better suited to this game than the while loop in the previous example. In the repeatwhile loop above, square += board[square] is always executed immediately after the loop’s while condition confirms that square is still on the board. This behavior removes the need for the array bounds check seen in the while loop version of the game described earlier.

Conditional Statements

It is often useful to execute different pieces of code based on certain conditions. You might want to run an extra piece of code when an error occurs, or to display a message when a value becomes too high or too low. To do this, you make parts of your code conditional.

Swift provides two ways to add conditional branches to your code: the if statement and the switch statement. Typically, you use the if statement to evaluate simple conditions with only a few possible outcomes. The switch statement is better suited to more complex conditions with multiple possible permutations and is useful in situations where pattern matching can help select an appropriate code branch to execute.

If

In its simplest form, the if statement has a single if condition. It executes a set of statements only if that condition is true.

var temperatureInFahrenheit = 30

if temperatureInFahrenheit <= 32 {

    print(“It’s very cold. Consider wearing a scarf.”)

}      // Prints “It’s very cold. Consider wearing a scarf.”

The example above checks whether the temperature is less than or equal to 32 degrees Fahrenheit (the freezing point of water). If it is, a message is printed. Otherwise, no message is printed, and code execution continues after the if statement’s closing brace.The if statement can provide an alternative set of statements, known as an else clause, for situations when the if condition is false. These statements are indicated by the else keyword.

 temperatureInFahrenheit = 40

if temperatureInFahrenheit <= 32 {

    print(“It’s very cold. Consider wearing a scarf.”)

} else {

    print(“It’s not that cold. Wear a t-shirt.”)

}      // Prints “It’s not that cold. Wear a t-shirt.” 

One of these two branches is always executed. Because the temperature has increased to 40 degrees Fahrenheit, it is no longer cold enough to advise wearing a scarf and so the else branch is triggered instead.You can chain multiple if statements together to consider additional clauses.

temperatureInFahrenheit = 90

if temperatureInFahrenheit <= 32 {

    print(“It’s very cold. Consider wearing a scarf.”)

} else if temperatureInFahrenheit >= 86 {

    print(“It’s really warm. Don’t forget to wear sunscreen.”)

} else {

    print(“It’s not that cold. Wear a t-shirt.”)

}    // Prints “It’s really warm. Don’t forget to wear sunscreen.” 

Here, an additional if statement was added to respond to particularly warm temperatures. The final else clause remains, and it prints a response for any temperatures that are neither too warm nor too cold.

The final else clause is optional, however, and can be excluded if the set of conditions does not need to be complete.

Switch

A switch statement considers a value and compares it against several possible matching patterns. It then executes an appropriate block of code, based on the first pattern that matches successfully. A switch statement provides an alternative to the if statement for responding to multiple potential states.

In its simplest form, a switch statement compares a value against one or more values of the same type.

switch some value to consider {

case value 1:

    respond to value 1

case value 2,

     value 3:

    respond to value 2 or 3

default:

    otherwise, do something else

}

Every switch statement consists of multiple possible cases, each of which begins with the case keyword. In addition to comparing against specific values, Swift provides several ways for each case to specify more complex matching patterns. Like the body of an if statement, each case is a separate branch of code execution. The switch statement determines which branch should be selected. This procedure is known as switching on the value that is being considered.

Every switch statement must be exhaustive. That is, every possible value of the type being considered must be matched by one of the switch cases. If it’s not appropriate to provide a case for every possible value, you can define a default case to cover any values that are not addressed explicitly. This default case is indicated by the default keyword, and must always appear last.

This example uses a switch statement to consider a single lowercase character called someCharacter:

let someCharacter:  = “z”

switch someCharacter {

case “a”:

    print(“The first letter of the alphabet”)

case “z”:

    print(“The last letter of the alphabet”)

default:

    print(“Some other character”)

}     // Prints “The last letter of the alphabet” 

The switch statement’s first case matches the first letter of the English alphabet, a, and its second case matches the last letter, z. Because the switch must have a case for every possible character, not just every alphabetic character, this switch statement uses a default case to match all characters other than a and z. This provision ensures that the switch statement is exhaustive.

No Implicit Fallthrough

In contrast with switch statements in C and Objective-C, switch statements in Swift do not fall through the bottom of each case and into the next one by default. Instead, the entire switch statement finishes its execution as soon as the first matching switch case is completed, without requiring an explicit break statement. This makes the switch statement safer and easier to use than the one in C and avoids executing more than one switch case by mistake.Although break is not required in Swift, you can use a break statement to match and ignore a particular case or to break out of a matched case before that case has completed its execution. The body of each case must contain at least one executable statement. It is not valid to write the following code, because the first case is empty:

let anotherCharacter:  = “a”

switch anotherCharacter {

case “a”: // Invalid, the case has an empty body

case “A”:

    print(“The letter A”)

default:

    print(“Not the letter A”)

}   // This will report a compile-time error.

Unlike a switch statement in C, this switch statement does not match both “a” and “A”. Rather, it reports a compile-time error that case “a”: does not contain any executable statements. This approach avoids accidental fallthrough from one case to another and makes for safer code that is clearer in its intent.To make a switch with a single case that matches both “a” and “A”, combine the two values into a compound case, separating the values with commas.

let anotherCharacter:  = “a”

switch anotherCharacter {

case “a”, “A”:

    print(“The letter A”)

default:

    print(“Not the letter A”)

}     // Prints “The letter A”

Interval Matching

Values in switch cases can be checked for their inclusion in an interval. This example uses number intervals to provide a natural-language count for numbers of any size:

 let approximateCount = 62

let countedThings = “moons orbiting Saturn”

let naturalCount:

switch approximateCount {

case 0:

    naturalCount = “no”

case 1..<5:

    naturalCount = “a few”

case 5..<12:

    naturalCount = “several”

case 12..<100:

    naturalCount = “dozens of”

case 100..<1000:

    naturalCount = “hundreds of”

default:

    naturalCount = “many”

}

print(“There are \(naturalCount) \(countedThings).”)

// Prints “There are dozens of moons orbiting Saturn.”  

In the above example, approximateCount is evaluated in a switch statement. Each case compares that value to a number or interval. Because the value of approximateCount falls between 12 and 100, naturalCount is assigned the value “dozens of”, and execution is transferred out of the switch statement.

Tuples

You can use tuples to test multiple values in the same switch statement. Each element of the tuple can be tested against a different value or interval of values. Alternatively, use the underscore character (_), also known as the wildcard pattern, to match any possible value.The example below takes an (x, y) point, expressed as a simple tuple of type (Int, Int), and categorizes it on the graph that follows the example.

let somePoint = (1, 1)

switch somePoint {

case (0, 0):

    print(\(somePoint) is at the origin”)

case (_, 0):

    print(\(somePoint) is on the x-axis”)

case (0, _):

    print(\(somePoint) is on the y-axis”)

case (-22, -22):

    print(\(somePoint) is inside the box”)

default:

    print(\(somePoint) is outside of the box”)

}      // Prints “(1, 1) is inside the box”   

   

The switch statement determines whether the point is at the origin (0, 0), on the red x-axis, on the orange y-axis, inside the blue 4-by-4 box centered on the origin, or outside of the box.

Swift allows multiple switch cases to consider the same value or values. In fact, the point (0, 0) could match all four of the cases in this example. However, if multiple matches are possible, the first matching case is always used. The point (0, 0) would match case (0, 0) first, and so all other matching cases would be ignored.

Value Bindings

A switch case can name the value or values it matches to temporary constants or variables, for use in the body of the case. This behavior is known as value binding, because the values are bound to temporary constants or variables within the case’s body.The example below takes an (x, y) point, expressed as a tuple of type (Int, Int):

 let anotherPoint = (2, 0)

switch anotherPoint {

case (let x, 0):

    print(“on the x-axis with an x value of \(x))

case (0, let y):

    print(“on the y-axis with a y value of \(y))

case let (x, y):

    print(“somewhere else at (\(x), \(y))”)

} // Prints “on the x-axis with an x value of 2”.

   

The switch statement determines whether the point is on the red x-axis, on the orange y-axis, or elsewhere (on neither axis).The three switch cases declare placeholder constants x and y, which temporarily take on one or both tuple values from anotherPoint. The first case, case (let x, 0), matches any point with a y value of 0 and assigns the point’s x value to the temporary constant x. Similarly, the second case, case (0, let y), matches any point with an x value of 0 and assigns the point’s y value to the temporary constant y.After the temporary constants are declared, they can be used within the case’s code block. Here, they are used to print the categorization of the point.

Where

A switch case can use a where clause to check for additional conditions.The example below categorizes an (x, y) point on the following graph:

 let yetAnotherPoint = (1, -1)

switch yetAnotherPoint {

case let (x, y) where x == y:

    print(“(\(x), \(y)) is on the line x == y”)

case let (x, y) where x == –y:

    print(“(\(x), \(y)) is on the line x == -y”)

case let (x, y):

    print(“(\(x), \(y)) is just some arbitrary point”)

}. // Prints “(1, -1) is on the line x == -y”

   

The switch statement determines whether the point is on the green diagonal line where x == y, on the purple diagonal line where x == -y, or neither.

Compound Cases

Multiple switch cases that share the same body can be combined by writing several patterns after case, with a comma between each of the patterns. If any of the patterns match, then the case is considered to match. The patterns can be written over multiple lines if the list is long. For example:

let someCharacter:  = “e”

switch someCharacter {

case “a”, “e”, “i”, “o”, “u”:

    print(\(someCharacter) is a vowel”)

case “b”, “c”, “d”, “f”, “g”, “h”, “j”, “k”, “l”, “m”,

     “n”, “p”, “q”, “r”, “s”, “t”, “v”, “w”, “x”, “y”, “z”:

    print(\(someCharacter) is a consonant”)

default:

    print(\(someCharacter) is not a vowel or a consonant”)

}      // Prints “e is a vowel”

The switch statement’s first case matches all five lowercase vowels in the English language. Similarly, its second case matches all lowercase English consonants. Finally, the default case matches any other character.

Control Transfer Statements

Control transfer statements change the order in which your code is executed, by transferring control from one piece of code to another. Swift has five control transfer statements:

continue

break

fallthrough

return

throw

Continue

The continue statement tells a loop to stop what it is doing and start again at the beginning of the next iteration through the loop. It says “I am done with the current loop iteration” without leaving the loop altogether.The following example removes all vowels and spaces from a lowercase string to create a cryptic puzzle phrase:

let puzzleInput = “great minds think alike”

var puzzleOutput = “”

let charactersToRemove: [] = [“a”, “e”, “i”, “o”, “u”, ” “]

for character in puzzleInput {

    if charactersToRemove.contains(character) {

        continue

    } else {

        puzzleOutput.append(character)

    }

}

print(puzzleOutput)    // Prints “grtmndsthnklk” 

The code above calls the continue keyword whenever it matches a vowel or a space, causing the current iteration of the loop to end immediately and to jump straight to the start of the next iteration.

Break

The break statement ends execution of an entire control flow statement immediately. The break statement can be used inside a switch or loop statement when you want to terminate the execution of the switch or loop statement earlier than would otherwise be the case.

Break in a Loop Statement

When used inside a loop statement, break ends the loop’s execution immediately and transfers control to the code after the loop’s closing brace (}). No further code from the current iteration of the loop is executed, and no further iterations of the loop are started.

Break in a Switch Statement

When used inside a switch statement, break causes the switch statement to end its execution immediately and to transfer control to the code after the switch statement’s closing brace (}).This behavior can be used to match and ignore one or more cases in a switch statement. Because Swift’s switch statement is exhaustive and does not allow empty cases, it is sometimes necessary to deliberately match and ignore a case in order to make your intentions explicit. You do this by writing the break statement as the entire body of the case you want to ignore. When that case is matched by the switch statement, the break statement inside the case ends the switch statement’s execution immediately.

A switch case that contains only a comment is reported as a compile-time error. Comments are not statements and do not cause a switch case to be ignored. Always use a break statement to ignore a switch case.

The following example switches on a Character value and determines whether it represents a number symbol in one of four languages. For brevity, multiple values are covered in a single switch case.

 let numberSymbol:  =   // Chinese symbol for the number 3

var possibleIntegerValue: ?

switch numberSymbol {

case “1”, ١, , :

    possibleIntegerValue = 1

case “2”, ٢, , :

    possibleIntegerValue = 2

case “3”, ٣, , :

    possibleIntegerValue = 3

case “4”, ٤, , :

    possibleIntegerValue = 4

default:

    break

}

if let integerValue = possibleIntegerValue {

    print(“The integer value of \(numberSymbol) is \(integerValue).”)

} else {

    print(“An integer value could not be found for \(numberSymbol).”)

}     // Prints “The integer value of is 3.” 

This example checks numberSymbol to determine whether it is a Latin, Arabic, Chinese, or Thai symbol for the numbers 1 to 4. If a match is found, one of the switch statement’s cases sets an optional Int? variable called possibleIntegerValue to an appropriate integer value.

After the switch statement completes its execution, the example uses optional binding to determine whether a value was found. The possibleIntegerValue variable has an implicit initial value of nil by virtue of being an optional type, and so the optional binding will succeed only if possibleIntegerValue was set to an actual value by one of the switch statement’s first four cases.Because it’s not practical to list every possible Character value in the example above, a default case handles any characters that are not matched. This default case does not need to perform any action, and so it is written with a single break statement as its body. As soon as the default case is matched, the break statement ends the switch statement’s execution, and code execution continues from the if let statement.

Fallthrough

In Swift, switch statements don’t fall through the bottom of each case and into the next one. That is, the entire switch statement completes its execution as soon as the first matching case is completed. By contrast, C requires you to insert an explicit break statement at the end of every switch case to prevent fallthrough. Avoiding default fallthrough means that Swift switch statements are much more concise and predictable than their counterparts in C, and thus they avoid executing multiple switch cases by mistake.

If you need C-style fallthrough behavior, you can opt in to this behavior on a case-by-case basis with the fallthrough keyword. The example below uses fallthrough to create a textual description of a number.

let integerToDescribe = 5

var description = “The number \(integerToDescribe) is”

switch integerToDescribe {

case 2, 3, 5, 7, 11, 13, 17, 19:

    description += ” a prime number, and also”

    fallthrough

default:

    description += ” an integer.”

}

print(description)

// Prints “The number 5 is a prime number, and also an integer.”

This example declares a new String variable called description and assigns it an initial value. The function then considers the value of integerToDescribe using a switch statement. If the value of integerToDescribe is one of the prime numbers in the list, the function appends text to the end of description, to note that the number is prime. It then uses the fallthrough keyword to “fall into” the default case as well. The default case adds some extra text to the end of the description, and the switch statement is complete.

Unless the value of integerToDescribe is in the list of known prime numbers, it is not matched by the first switch case at all. Because there are no other specific cases, integerToDescribe is matched by the default case.

After the switch statement has finished executing, the number’s description is printed using the print(_:separator:terminator:) function. In this example, the number 5 is correctly identified as a prime number.The fallthrough keyword does not check the case conditions for the switch case that it causes execution to fall into. The fallthrough keyword simply causes code execution to move directly to the statements inside the next case (or default case) block, as in C’s standard switch statement behavior.

Labeled Statements

In Swift, you can nest loops and conditional statements inside other loops and conditional statements to create complex control flow structures. However, loops and conditional statements can both use the break statement to end their execution prematurely. Therefore, it is sometimes useful to be explicit about which loop or conditional statement you want a break statement to terminate. Similarly, if you have multiple nested loops, it can be useful to be explicit about which loop the continue statement should affect.To achieve these aims, you can mark a loop statement or conditional statement with a statement label. With a conditional statement, you can use a statement label with the break statement to end the execution of the labeled statement. With a loop statement, you can use a statement label with the break or continue statement to end or continue the execution of the labeled statement.

A labeled statement is indicated by placing a label on the same line as the statement’s introducer keyword, followed by a colon. Here’s an example of this syntax for a while loop, although the principle is the same for all loops and switch statements:

label name: while condition {

    statements

}

The following example uses the break and continue statements with a labeled while loop for an adapted version of the Snakes and Ladders game that you saw earlier in this chapter. This time around, the game has an extra rule:

To win, you must land exactly on square 25.

If a particular dice roll would take you beyond square 25, you must roll again until you roll the exact number needed to land on square 25.

The game board is the same as before.

   

The values of finalSquare, board, square, and diceRoll are initialized in the same way as before:

let finalSquare = 25

var board = [Int](repeating: 0, count: finalSquare + 1)

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02

board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

var square = 0

var diceRoll = 0

This version of the game uses a while loop and a switch statement to implement the game’s logic. The while loop has a statement label called gameLoop to indicate that it is the main game loop for the Snakes and Ladders game.

The while loop’s condition is while square != finalSquare, to reflect that you must land exactly on square 25.

gameLoop: while square != finalSquare {

    diceRoll += 1

    if diceRoll == 7 { diceRoll = 1 }

    switch square + diceRoll {

    case finalSquare:

        // diceRoll will move us to the final square, so the game is over

        break gameLoop

    case let newSquare where newSquare > finalSquare:

        // diceRoll will move us beyond the final square, so roll again

        continue gameLoop

    default:

        // this is a valid move, so find out its effect

        square += diceRoll

        square += board[square]

    }

}

print(“Game over!”

The dice is rolled at the start of each loop. Rather than moving the player immediately, the loop uses a switch statement to consider the result of the move and to determine whether the move is allowed:If the dice roll will move the player onto the final square, the game is over. The break gameLoop statement transfers control to the first line of code outside of the while loop, which ends the game.

If the dice roll will move the player beyond the final square, the move is invalid and the player needs to roll again. The continue gameLoop statement ends the current while loop iteration and begins the next iteration of the loop.In all other cases, the dice roll is a valid move. The player moves forward by diceRoll squares, and the game logic checks for any snakes and ladders. The loop then ends, and control returns to the while condition to decide whether another turn is required.

Early Exit

A guard statement, like an if statement, executes statements depending on the Boolean value of an expression. You use a guard statement to require that a condition must be true in order for the code after the guard statement to be executed. Unlike an if statement, a guard statement always has an else clause—the code inside the else clause is executed if the condition is not true.

func greet(person: [: ]) {

    guard let name = person[“name”] else {

        return

    }

    

    print(“Hello \(name)!”)

    

    guard let location = person[“location”] else {

        print(“I hope the weather is nice near you.”)

        return

    }

    

    print(“I hope the weather is nice in \(location).”)

}

greet(person: [“name”: “John”])

// Prints “Hello John!”

// Prints “I hope the weather is nice near you.”

greet(person: [“name”: “Jane”, “location”: “Cupertino”])

// Prints “Hello Jane!”

// Prints “I hope the weather is nice in Cupertino.” 

If the guard statement’s condition is met, code execution continues after the guard statement’s closing brace. Any variables or constants that were assigned values using an optional binding as part of the condition are available for the rest of the code block that the guard statement appears in.

If that condition is not met, the code inside the else branch is executed. That branch must transfer control to exit the code block in which the guard statement appears. It can do this with a control transfer statement such as return, break, continue, or throw, or it can call a function or method that doesn’t return, such as fatalError(_:file:line:).Using a guard statement for requirements improves the readability of your code, compared to doing the same check with an if statement. It lets you write the code that’s typically executed without wrapping it in an else block, and it lets you keep the code that handles a violated requirement next to the requirement.

Checking API Availability

Swift has built-in support for checking API availability, which ensures that you don’t accidentally use APIs that are unavailable on a given deployment target.

The compiler uses availability information in the SDK to verify that all of the APIs used in your code are available on the deployment target specified by your project. Swift reports an error at compile time if you try to use an API that isn’t available.You use an availability condition in an if or guard statement to conditionally execute a block of code, depending on whether the APIs you want to use are available at runtime. The compiler uses the information from the availability condition when it verifies that the APIs in that block of code are available.

if #available(iOS 10, macOS 10.12, *) {

    // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS

} else {

    // Fall back to earlier iOS and macOS APIs

}

The availability condition above specifies that in iOS, the body of the if statement executes only in iOS 10 and later; in macOS, only in macOS 10.12 and later. The last argument, *, is required and specifies that on any other platform, the body of the if executes on the minimum deployment target specified by your target.In its general form, the availability condition takes a list of platform names and versions. You use platform names such as iOS, macOS, watchOS, and tvOS—for the full list, see Declaration Attributes. In addition to specifying major version numbers like iOS 8 or macOS 10.10, you can specify minor versions numbers like iOS 8.3 and macOS 10.10.3.

if #available(platform name version, …, *) {

    statements to execute if the APIs are available

} else {

    fallback statements to execute if the APIs are unavailable

}

Functions

Functions are self-contained chunks of code that perform a specific task. You give a function a name that identifies what it does, and this name is used to “call” the function to perform its task when needed.Swift’s unified function syntax is flexible enough to express anything from a simple C-style function with no parameter names to a complex Objective-C-style method with names and argument labels for each parameter. Parameters can provide default values to simplify function calls and can be passed as in-out parameters, which modify a passed variable once the function has completed its execution.

Every function in Swift has a type, consisting of the function’s parameter types and return type. You can use this type like any other type in Swift, which makes it easy to pass functions as parameters to other functions, and to return functions from functions. Functions can also be written within other functions to encapsulate useful functionality within a nested function scope.

Defining and Calling Functions

When you define a function, you can optionally define one or more named, typed values that the function takes as input, known as parameters. You can also optionally define a type of value that the function will pass back as output when it is done, known as its return type.Every function has a function name, which describes the task that the function performs. To use a function, you “call” that function with its name and pass it input values (known as arguments) that match the types of the function’s parameters. A function’s arguments must always be provided in the same order as the function’s parameter list.

The function in the example below is called greet(person:), because that’s what it does—it takes a person’s name as input and returns a greeting for that person. To accomplish this, you define one input parameter—a String value called person—and a return type of String, which will contain a greeting for that person:

func greet(person: ) ->  {

    let greeting = “Hello, “ + person + “!”

    return greeting

}

All of this information is rolled up into the function’s definition, which is prefixed with the func keyword. You indicate the function’s return type with the return arrow -> (a hyphen followed by a right angle bracket), which is followed by the name of the type to return.

The definition describes what the function does, what it expects to receive, and what it returns when it is done. The definition makes it easy for the function to be called unambiguously from elsewhere in your code:

print(greet(person: “Anna”))       // Prints “Hello, Anna!”

print(greet(person: “Brian”))       // Prints “Hello, Brian!”

You call the greet(person:) function by passing it a String value after the person argument label, such as greet(person: “Anna”). Because the function returns a String value, greet(person:) can be wrapped in a call to the print(_:separator:terminator:) function to print that string and see its return value, as shown above.The print(_:separator:terminator:) function doesn’t have a label for its first argument, and its other arguments are optional because they have a default value. These variations on function syntax are discussed below in Function Argument Labels and Parameter Names and Default Parameter Values.

To make the body of this function shorter, you can combine the message creation and the return statement into one line:

func greetAgain(person: ) ->  {

    return “Hello again, “ + person + “!”

}

print(greetAgain(person: “Anna”))       // Prints “Hello again, Anna!”

Function Parameters and Return Values

Function parameters and return values are extremely flexible in Swift. You can define anything from a simple utility function with a single unnamed parameter to a complex function with expressive parameter names and different parameter options.

Functions Without Parameters

Functions are not required to define input parameters. Here’s a function with no input parameters, which always returns the same String message whenever it is called:

func sayHelloWorld() ->  {

    return “hello, world”

}

print(sayHelloWorld())    // Prints “hello, world”

The function definition still needs parentheses after the function’s name, even though it does not take any parameters. The function name is also followed by an empty pair of parentheses when the function is called.

Functions With Multiple Parameters

Functions can have multiple input parameters, which are written within the function’s parentheses, separated by commas.This function takes a person’s name and whether they have already been greeted as input, and returns an appropriate greeting for that person:

classboxstart func greet(person: , alreadyGreeted: ) ->  {

    if alreadyGreeted {

        return greetAgain(person: person)

    } else {

        return greet(person: person)

    }

}

print(greet(person: “Tim”, alreadyGreeted: true))

// Prints “Hello again, Tim!” classbox

You call the greet(person:alreadyGreeted:) function by passing it both a String argument value labeled person and a Bool argument value labeled alreadyGreeted in parentheses, separated by commas.

Functions Without Return Values

Functions are not required to define a return type. Here’s a version of the greet(person:) function, which prints its own String value rather than returning it:

func greet(person: ) {

    print(“Hello, \(person)!”)

}

greet(person: “Dave”)       // Prints “Hello, Dave!”

Because it does not need to return a value, the function’s definition does not include the return arrow (->) or a return type.

The return value of a function can be ignored when it is called:

func printAndCount(string: ) ->  {

    print(string)

    return string.count

}

func printWithoutCounting(string: ) {

    let _ = printAndCount(string: string)

}

printAndCount(string: “hello, world”)     // prints “hello, world” and returns a value of 12

printWithoutCounting(string: “hello, world”)    // prints “hello, world” but does not return a value

The first function, printAndCount(string:), prints a string, and then returns its character count as an Int. The second function, printWithoutCounting(string:), calls the first function, but ignores its return value. When the second function is called, the message is still printed by the first function, but the returned value is not used.Return values can be ignored, but a function that says it will return a value must always do so. A function with a defined return type cannot allow control to fall out of the bottom of the function without returning a value, and attempting to do so will result in a compile-time error.

Functions with Multiple Return Values

You can use a tuple type as the return type for a function to return multiple values as part of one compound return value.The example below defines a function called minMax(array:), which finds the smallest and largest numbers in an array of Int values:

classboxstart func minMax(array: []) -> (min: , max: ) {

    var currentMin = array[0]

    var currentMax = array[0]

    for value in array[1..<array.count] {

        if value < currentMin {

            currentMin = value

        } else if value > currentMax {

            currentMax = value

        }

    }

    return (currentMin, currentMax)

}classbox

The minMax(array:) function returns a tuple containing two Int values. These values are labeled min and max so that they can be accessed by name when querying the function’s return value.The body of the minMax(array:) function starts by setting two working variables called currentMin and currentMax to the value of the first integer in the array. The function then iterates over the remaining values in the array and checks each value to see if it is smaller or larger than the values of currentMin and currentMax respectively. Finally, the overall minimum and maximum values are returned as a tuple of two Int values.Because the tuple’s member values are named as part of the function’s return type, they can be accessed with dot syntax to retrieve the minimum and maximum found values:

let bounds = minMax(array: [8, -6, 2, 109, 3, 71])

print(“min is \(bounds.min) and max is \(bounds.max))

// Prints “min is -6 and max is 109”

Optional Tuple Return Types

If the tuple type to be returned from a function has the potential to have “no value” for the entire tuple, you can use an optional tuple return type to reflect the fact that the entire tuple can be nil. You write an optional tuple return type by placing a question mark after the tuple type’s closing parenthesis, such as (Int, Int)? or (String, Int, Bool)?.An optional tuple type such as (Int, Int)? is different from a tuple that contains optional types such as (Int?, Int?). With an optional tuple type, the entire tuple is optional, not just each individual value within the tuple.

The minMax(array:) function above returns a tuple containing two Int values. However, the function does not perform any safety checks on the array it is passed. If the array argument contains an empty array, the minMax(array:) function, as defined above, will trigger a runtime error when attempting to access array[0].To handle an empty array safely, write the minMax(array:) function with an optional tuple return type and return a value of nil when the array is empty:

classboxstart func minMax(array: []) -> (min: , max: )? {

    if array.isEmpty { return nil }

    var currentMin = array[0]

    var currentMax = array[0]

    for value in array[1..<array.count] {

        if value < currentMin {

            currentMin = value

        } else if value > currentMax {

            currentMax = value

        }

    }

    return (currentMin, currentMax)

}

You can use optional binding to check whether this version of the minMax(array:) function returns an actual tuple value or nil:

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {

    print(“min is \(bounds.min) and max is \(bounds.max))

}

// Prints “min is -6 and max is 109” classbox

Function Argument Labels and Parameter Names

Each function parameter has both an argument label and a parameter name. The argument label is used when calling the function; each argument is written in the function call with its argument label before it. The parameter name is used in the implementation of the function. By default, parameters use their parameter name as their argument label.

func someFunction(firstParameterName: , secondParameterName: ) {

    // In the function body, firstParameterName and secondParameterName

    // refer to the argument values for the first and second parameters.

}

someFunction(firstParameterName: 1, secondParameterName: 2)

All parameters must have unique names. Although it’s possible for multiple parameters to have the same argument label, unique argument labels help make your code more readable.

Specifying Argument Labels

You write an argument label before the parameter name, separated by a space:

func someFunction(argumentLabel parameterName: ) {

    // In the function body, parameterName refers to the argument value

    // for that parameter.

}

Here’s a variation of the greet(person:) function that takes a person’s name and hometown and returns a greeting:

func greet(person: , from hometown: ) ->  {

    return “Hello \(person)!  Glad you could visit from \(hometown).”

}

print(greet(person: “Bill”, from: “Cupertino”))

// Prints “Hello Bill!Glad you could visit from Cupertino.”

The use of argument labels can allow a function to be called in an expressive, sentence-like manner, while still providing a function body that is readable and clear in intent.

Omitting Argument Labels

If you don’t want an argument label for a parameter, write an underscore (_) instead of an explicit argument label for that parameter.

func someFunction(_ firstParameterName: , secondParameterName: ) {

    // In the function body, firstParameterName and secondParameterName

    // refer to the argument values for the first and second parameters.

}

someFunction(1, secondParameterName: 2)

If a parameter has an argument label, the argument must be labeled when you call the function.

Default Parameter Values

You can define a default value for any parameter in a function by assigning a value to the parameter after that parameter’s type. If a default value is defined, you can omit that parameter when calling the function.

func someFunction(parameterWithoutDefault: , parameterWithDefault:  = 12) {

    // If you omit the second argument when calling this function, then

    // the value of parameterWithDefault is 12 inside the function body.

}

someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault is 6

someFunction(parameterWithoutDefault: 4) // parameterWithDefault is 12

Place parameters that don’t have default values at the beginning of a function’s parameter list, before the parameters that have default values. Parameters that don’t have default values are usually more important to the function’s meaning—writing them first makes it easier to recognize that the same function is being called, regardless of whether any default parameters are omitted.

Variadic Parameters

A variadic parameter accepts zero or more values of a specified type. You use a variadic parameter to specify that the parameter can be passed a varying number of input values when the function is called. Write variadic parameters by inserting three period characters () after the parameter’s type name.The values passed to a variadic parameter are made available within the function’s body as an array of the appropriate type. For example, a variadic parameter with a name of numbers and a type of Double… is made available within the function’s body as a constant array called numbers of type [Double].

The example below calculates the arithmetic mean (also known as the average) for a list of numbers of any length:

classboxstart func arithmeticMean(_ numbers: …) ->  {

    var total:  = 0

    for number in numbers {

        total += number

    }

    return total / Double(numbers.count)

}

arithmeticMean(1, 2, 3, 4, 5)

// returns 3.0, which is the arithmetic mean of these five numbers

arithmeticMean(3, 8.25, 18.75)

// returns 10.0, which is the arithmetic mean of these three numbers classbox

In-Out Parameters

Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you can’t change the value of a parameter by mistake. If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.You write an in-out parameter by placing the inout keyword right before a parameter’s type. An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value. For a detailed discussion of the behavior of in-out parameters and associated compiler optimizations, see In-Out Parameters.

You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an in-out parameter, to indicate that it can be modified by the function.In-out parameters cannot have default values, and variadic parameters cannot be marked as inout.

Here’s an example of a function called swapTwoInts(_:_:), which has two in-out integer parameters called a and b:

func swapTwoInts(_ a: inout , _ b: inout ) {

    let temporaryA = a

    a = b

    b = temporaryA

}

The swapTwoInts(_:_:) function simply swaps the value of b into a, and the value of a into b. The function performs this swap by storing the value of a in a temporary constant called temporaryA, assigning the value of b to a, and then assigning temporaryA to b.

You can call the swapTwoInts(_:_:) function with two variables of type Int to swap their values. Note that the names of someInt and anotherInt are prefixed with an ampersand when they are passed to the swapTwoInts(_:_:) function:

classboxstart var someInt = 3

var anotherInt = 107

swapTwoInts(&someInt, &anotherInt)

print(“someInt is now \(someInt), and anotherInt is now \(anotherInt))

// Prints “someInt is now 107, and anotherInt is now 3” classbox

The example above shows that the original values of someInt and anotherInt are modified by the swapTwoInts(_:_:) function, even though they were originally defined outside of the function.

Function Types

Every function has a specific function type, made up of the parameter types and the return type of the function.

For example:

func addTwoInts(_ a: , _ b: ) ->  {

    return a + b

}

func multiplyTwoInts(_ a: , _ b: ) ->  {

    return a * b

}

This example defines two simple mathematical functions called addTwoInts and multiplyTwoInts. These functions each take two Int values, and return an Int value, which is the result of performing an appropriate mathematical operation.

The type of both of these functions is (Int, Int) -> Int. This can be read as:

“A function that has two parameters, both of type Int, and that returns a value of type Int.”

Using Function Types

You use function types just like any other types in Swift. For example, you can define a constant or variable to be of a function type and assign an appropriate function to that variable:

var mathFunction: (, ) ->  = addTwoInts

This can be read as:

“Define a variable called mathFunction, which has a type of ‘a function that takes two Int values, and returns an Int value.’ Set this new variable to refer to the function called addTwoInts.”

The addTwoInts(_:_:) function has the same type as the mathFunction variable, and so this assignment is allowed by Swift’s type-checker.

You can now call the assigned function with the name mathFunction:

print(“Result: \(mathFunction(2, 3)))        // Prints “Result: 5”

A different function with the same matching type can be assigned to the same variable, in the same way as for nonfunction types:

mathFunction = multiplyTwoInts

print(“Result: \(mathFunction(2, 3)))       // Prints “Result: 6”

As with any other type, you can leave it to Swift to infer the function type when you assign a function to a constant or variable:

let anotherMathFunction = addTwoInts

// anotherMathFunction is inferred to be of type (Int, Int) -> Int

Function Types as Parameter Types

You can use a function type such as (Int, Int) -> Int as a parameter type for another function. This enables you to leave some aspects of a function’s implementation for the function’s caller to provide when the function is called.Here’s an example to print the results of the math functions from above:

func printMathResult(_ mathFunction: (, ) -> , _ a: , _ b: ) {

    print(“Result: \(mathFunction(a, b)))

}

printMathResult(addTwoInts, 3, 5)     // Prints “Result: 8”

This example defines a function called printMathResult(_:_:_:), which has three parameters. The first parameter is called mathFunction, and is of type (Int, Int) -> Int. You can pass any function of that type as the argument for this first parameter. The second and third parameters are called a and b, and are both of type Int. These are used as the two input values for the provided math function.

When printMathResult(_:_:_:) is called, it is passed the addTwoInts(_:_:) function, and the integer values 3 and 5. It calls the provided function with the values 3 and 5, and prints the result of 8.

Function Types as Return Types

You can use a function type as the return type of another function. You do this by writing a complete function type immediately after the return arrow (->) of the returning function.The next example defines two simple functions called stepForward(_:) and stepBackward(_:). The stepForward(_:) function returns a value one more than its input value, and the stepBackward(_:) function returns a value one less than its input value. Both functions have a type of (Int) -> Int:

func stepForward(_ input: ) ->  {

    return input + 1

}

func stepBackward(_ input: ) ->  {

    return input1

}

Here’s a function called chooseStepFunction(backward:), whose return type is (Int) -> Int. The chooseStepFunction(backward:) function returns the stepForward(_:) function or the stepBackward(_:) function based on a Boolean parameter called backward:

func chooseStepFunction(backward: ) -> () ->  {

    return backward ? stepBackward : stepForward

}

You can now use chooseStepFunction(backward:) to obtain a function that will step in one direction or the other:

var currentValue = 3

let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)

// moveNearerToZero now refers to the stepBackward() function

The preceding example determines whether a positive or negative step is needed to move a variable called currentValue progressively closer to zero. currentValue has an initial value of 3, which means that currentValue > 0 returns true, causing chooseStepFunction(backward:) to return the stepBackward(_:) function. A reference to the returned function is stored in a constant called moveNearerToZero.

Now that moveNearerToZero refers to the correct function, it can be used to count to zero:

print(“Counting to zero:”)

// Counting to zero:

while currentValue != 0 {

    print(\(currentValue)… “)

    currentValue = moveNearerToZero(currentValue)

}

print(“zero!”)

// 3…

// 2…

// 1…

// zero!

Nested Functions

All of the functions you have encountered so far in this chapter have been examples of global functions, which are defined at a global scope. You can also define functions inside the bodies of other functions, known as nested functions.Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.You can rewrite the chooseStepFunction(backward:) example above to use and return nested functions:

classboxstart func chooseStepFunction(backward: ) -> () ->  {

    func stepForward(input: ) ->  { return input + 1 }

    func stepBackward(input: ) ->  { return input1 }

    return backward ? stepBackward : stepForward

}

var currentValue = -4

let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)

// moveNearerToZero now refers to the nested stepForward() function

while currentValue != 0 {

    print(\(currentValue)… “)

    currentValue = moveNearerToZero(currentValue)

}

print(“zero!”)

// -4…

// -3…

// -2…

// -1…

// zero! classbox

‌‌Closures

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

Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables. Swift handles all of the memory management of capturing for you.Global and nested functions, as introduced in Functions, are actually special cases of closures. Closures take one of three forms:

Global functions are closures that have a name and do not capture any values.

Nested functions are closures that have a name and can capture values from their enclosing function.

Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

Swift’s closure expressions have a clean, clear style, with optimizations that encourage brief, clutter-free syntax in common scenarios. These optimizations include:

Inferring parameter and return value types from context

Implicit returns from single-expression closures

Shorthand argument names

Trailing closure syntax

Closure Expressions

Nested functions, as introduced in Nested Functions, are a convenient means of naming and defining self-contained blocks of code as part of a larger function. However, it is sometimes useful to write shorter versions of function-like constructs without a full declaration and name. This is particularly true when you work with functions or methods that take functions as one or more of their arguments.

Closure expressions are a way to write inline closures in a brief, focused syntax. Closure expressions provide several syntax optimizations for writing closures in a shortened form without loss of clarity or intent. The closure expression examples below illustrate these optimizations by refining a single example of the sorted(by:) method over several iterations, each of which expresses the same functionality in a more succinct way.

The Sorted Method

Swift’s standard library provides a method called sorted(by:), which sorts an array of values of a known type, based on the output of a sorting closure that you provide. Once it completes the sorting process, the sorted(by:) method returns a new array of the same type and size as the old one, with its elements in the correct sorted order. The original array is not modified by the sorted(by:) method.The closure expression examples below use the sorted(by:) method to sort an array of String values in reverse alphabetical order. Here’s the initial array to be sorted:

let names = [“Chris”, “Alex”, “Ewa”, “Barry”, “Daniella”]

The sorted(by:) method accepts a closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the values are sorted. The sorting closure needs to return true if the first value should appear before the second value, and false otherwise.This example is sorting an array of String values, and so the sorting closure needs to be a function of type (String, String) -> Bool.

One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as an argument to the sorted(by:) method:

func backward(_ s1: , _ s2: ) ->  {

    return s1 > s2

}

var reversedNames = names.sorted(by: backward)

// reversedNames is equal to [“Ewa”, “Daniella”, “Chris”, “Barry”, “Alex”]

If the first string (s1) is greater than the second string (s2), the backward(_:_:) function will return true, indicating that s1 should appear before s2 in the sorted array. For characters in strings, “greater than” means “appears later in the alphabet than”. This means that the letter “B” is “greater than” the letter “A”, and the string “Tom” is greater than the string “Tim”. This gives a reverse alphabetical sort, with “Barry” being placed before “Alex”, and so on.

However, this is a rather long-winded way to write what is essentially a single-expression function (a > b). In this example, it would be preferable to write the sorting closure inline, using closure expression syntax.

Closure Expression Syntax

Closure expression syntax has the following general form:

{ (parameters) -> return type in

    statements

}

The parameters in closure expression syntax can be in-out parameters, but they can’t have a default value. Variadic parameters can be used if you name the variadic parameter. Tuples can also be used as parameter types and return types.

The example below shows a closure expression version of the backward(_:_:) function from earlier:

reversedNames = names.sorted(by: { (s1: , s2: ) ->  in

    return s1 > s2

})

Note that the declaration of parameters and return type for this inline closure is identical to the declaration from the backward(_:_:) function. In both cases, it is written as (s1: String, s2: String) -> Bool. However, for the inline closure expression, the parameters and return type are written inside the curly braces, not outside of them.

The start of the closure’s body is introduced by the in keyword. This keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.Because the body of the closure is so short, it can even be written on a single line:

reversedNames = names.sorted(by: { (s1: , s2: ) ->  in return s1 > s2 } )

This illustrates that the overall call to the sorted(by:) method has remained the same. A pair of parentheses still wrap the entire argument for the method. However, that argument is now an inline closure.

Inferring Type From Context

Because the sorting closure is passed as an argument to a method, Swift can infer the types of its parameters and the type of the value it returns. The sorted(by:) method is being called on an array of strings, so its argument must be a function of type (String, String) -> Bool. This means that the (String, String) and Bool types do not need to be written as part of the closure expression’s definition. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted:

reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

It is always possible to infer the parameter types and return type when passing a closure to a function or method as an inline closure expression. As a result, you never need to write an inline closure in its fullest form when the closure is used as a function or method argument.

Implicit Returns from Single-Expression Closures

Single-expression closures can implicitly return the result of their single expression by omitting the return keyword from their declaration, as in this version of the previous example:

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

Here, the function type of the sorted(by:) method’s argument makes it clear that a Bool value must be returned by the closure. Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted.

Shorthand Argument Names

Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body:

reversedNames = names.sorted(by: { $0 > $1 } )

Here, $0 and $1 refer to the closure’s first and second String arguments.

Operator Methods

There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a method that has two parameters of type String, and returns a value of type Bool. This exactly matches the method type needed by the sorted(by:) method. Therefore, you can simply pass in the greater-than operator, and Swift will infer that you want to use its string-specific implementation:

reversedNames = names.sorted(by: >)

Trailing Closures

If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. A trailing closure is written after the function call’s parentheses, even though it is still an argument to the function. When you use the trailing closure syntax, you don’t write the argument label for the closure as part of the function call.

classboxstart func someFunctionThatTakesAClosure(closure: () -> ) {

    // function body goes here

}

// Here’s how you call this function without using a trailing closure:

someFunctionThatTakesAClosure(closure: {

    // closure’s body goes here

})

// Here’s how you call this function with a trailing closure instead:

someFunctionThatTakesAClosure() {

    // trailing closure’s body goes here

}classbox

The string-sorting closure from the Closure Expression Syntax section above can be written outside of the sorted(by:) method’s parentheses as a trailing closure:

reversedNames = names.sorted() { $0 > $1 }

If a closure expression is provided as the function or method’s only argument and you provide that expression as a trailing closure, you do not need to write a pair of parentheses () after the function or method’s name when you call the function:

reversedNames = names.sorted { $0 > $1 }

Trailing closures are most useful when the closure is sufficiently long that it is not possible to write it inline on a single line. As an example, Swift’s Array type has a map(_:) method which takes a closure expression as its single argument. The closure is called once for each item in the array, and returns an alternative mapped value (possibly of some other type) for that item. The nature of the mapping and the type of the returned value is left up to the closure to specify.After applying the provided closure to each array element, the map(_:) method returns a new array containing all of the new mapped values, in the same order as their corresponding values in the original array.

Here’s how you can use the map(_:) method with a trailing closure to convert an array of Int values into an array of String values. The array [16, 58, 510] is used to create the new array [“OneSix”, “FiveEight”, “FiveOneZero”]:

let digitNames = [

    0: “Zero”, 1: “One”, 2: “Two”,   3: “Three”, 4: “Four”,

    5: “Five”, 6: “Six”, 7: “Seven”, 8: “Eight”, 9: “Nine”

]

let numbers = [16, 58, 510]

The code above creates a dictionary of mappings between the integer digits and English-language versions of their names. It also defines an array of integers, ready to be converted into strings.

You can now use the numbers array to create an array of String values, by passing a closure expression to the array’s map(_:) method as a trailing closure:

classboxstart let strings = numbers.map { (number) ->  in

    var number = number

    var output = “”

    repeat {

        output = digitNames[number % 10]! + output

        number /= 10

    } while number > 0

    return output

}

// strings is inferred to be of type [String]

// its value is [“OneSix”, “FiveEight”, “FiveOneZero”] classbox

The map(_:) method calls the closure expression once for each item in the array. You do not need to specify the type of the closure’s input parameter, number, because the type can be inferred from the values in the array to be mapped.In this example, the variable number is initialized with the value of the closure’s number parameter, so that the value can be modified within the closure body. (The parameters to functions and closures are always constants.) The closure expression also specifies a return type of String, to indicate the type that will be stored in the mapped output array.

The closure expression builds a string called output each time it is called. It calculates the last digit of number by using the remainder operator (number % 10), and uses this digit to look up an appropriate string in the digitNames dictionary. The closure can be used to create a string representation of any integer greater than zero.The string retrieved from the digitNames dictionary is added to the front of output, effectively building a string version of the number in reverse. (The expression number % 10 gives a value of 6 for 16, 8 for 58, and 0 for 510.)The process is repeated until number is equal to 0, at which point the output string is returned by the closure, and is added to the output array by the map(_:) method.

The use of trailing closure syntax in the example above neatly encapsulates the closure’s functionality immediately after the function that closure supports, without needing to wrap the entire closure within the map(_:) method’s outer parentheses.

Capturing Values

A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.In Swift, the simplest form of a closure that can capture values is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.

Here’s an example of a function called makeIncrementer, which contains a nested function called incrementer. The nested incrementer() function captures two values, runningTotal and amount, from its surrounding context. After capturing these values, incrementer is returned by makeIncrementer as a closure that increments runningTotal by amount each time it is called.

classboxstartfunc makeIncrementer(forIncrement amount: ) -> () ->  {

    var runningTotal = 0

    func incrementer() ->  {

        runningTotal += amount

        return runningTotal

    }

    return incrementer

}classboxs

The return type of makeIncrementer is () -> Int. This means that it returns a function, rather than a simple value. The function it returns has no parameters, and returns an Int value each time it is called. To learn how functions can return other functions, see Function Types as Return Types.

The makeIncrementer(forIncrement:) function defines an integer variable called runningTotal, to store the current running total of the incrementer that will be returned. This variable is initialized with a value of 0.

The makeIncrementer(forIncrement:) function has a single Int parameter with an argument label of forIncrement, and a parameter name of amount. The argument value passed to this parameter specifies how much runningTotal should be incremented by each time the returned incrementer function is called. The makeIncrementer function defines a nested function called incrementer, which performs the actual incrementing. This function simply adds amount to runningTotal, and returns the result.

When considered in isolation, the nested incrementer() function might seem unusual:

func incrementer() ->  {

    runningTotal += amount

    return runningTotal

}

The incrementer() function doesn’t have any parameters, and yet it refers to runningTotal and amount from within its function body. It does this by capturing a reference to runningTotal and amount from the surrounding function and using them within its own function body. Capturing by reference ensures that runningTotal and amount do not disappear when the call to makeIncrementer ends, and also ensures that runningTotal is available the next time the incrementer function is called.As an optimization, Swift may instead capture and store a copy of a value if that value is not mutated by a closure, and if the value is not mutated after the closure is created.

Swift also handles all memory management involved in disposing of variables when they are no longer needed.

Here’s an example of makeIncrementer in action:

let incrementByTen = makeIncrementer(forIncrement: 10)

This example sets a constant called incrementByTen to refer to an incrementer function that adds 10 to its runningTotal variable each time it is called. Calling the function multiple times shows this behavior in action:

incrementByTen()     // returns a value of 10

incrementByTen()      // returns a value of 20

incrementByTen()        // returns a value of 30

If you create a second incrementer, it will have its own stored reference to a new, separate runningTotal variable:

let incrementBySeven = makeIncrementer(forIncrement: 7)

incrementBySeven()     // returns a value of 7

Calling the original incrementer (incrementByTen) again continues to increment its own runningTotal variable, and does not affect the variable captured by incrementBySeven:

incrementByTen()     // returns a value of 40

Closures Are Reference Types

In the example above, incrementBySeven and incrementByTen are constants, but the closures these constants refer to are still able to increment the runningTotal variables that they have captured. This is because functions and closures are reference types.Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. In the example above, it is the choice of closure that incrementByTen refers to that is constant, and not the contents of the closure itself.

This also means that if you assign a closure to two different constants or variables, both of those constants or variables will refer to the same closure:

let alsoIncrementByTen = incrementByTen

alsoIncrementByTen()

// returns a value of 50

Escaping Closures

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

One way that a closure can escape is by being stored in a variable that is defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed—the closure needs to escape, to be called later. For example:

var completionHandlers: [() -> ] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping () -> ) {

    completionHandlers.append(completionHandler)

}

The someFunctionWithEscapingClosure(_:) function takes a closure as its argument and adds it to an array that’s declared outside the function. If you didn’t mark the parameter of this function with @escaping, you would get a compile-time error.

Marking a closure with @escaping means you have to refer to self explicitly within the closure. For example, in the code below, the closure passed to someFunctionWithEscapingClosure(_:) is an escaping closure, which means it needs to refer to self explicitly. In contrast, the closure passed to someFunctionWithNonescapingClosure(_:) is a nonescaping closure, which means it can refer to self implicitly.

classboxstart func someFunctionWithNonescapingClosure(closure: () -> ) {

    closure()

}

class SomeClass {

    var x = 10

    func doSomething() {

        someFunctionWithEscapingClosure { self.x = 100 }

        someFunctionWithNonescapingClosure { x = 200 }

    }

}

let instance = SomeClass()

instance.doSomething()

print(instance.x)

// Prints “200”

completionHandlers.first?()

print(instance.x)

// Prints “100” classbox

Autoclosures

An autoclosure is a closure that is automatically created to wrap an expression that’s being passed as an argument to a function. It doesn’t take any arguments, and when it’s called, it returns the value of the expression that’s wrapped inside of it. This syntactic convenience lets you omit braces around a function’s parameter by writing a normal expression instead of an explicit closure.

It’s common to call functions that take autoclosures, but it’s not common to implement that kind of function. For example, the assert(condition:message:file:line:) function takes an autoclosure for its condition and message parameters; its condition parameter is evaluated only in debug builds and its message parameter is evaluated only if condition is false.

An autoclosure lets you delay evaluation, because the code inside isn’t run until you call the closure. Delaying evaluation is useful for code that has side effects or is computationally expensive, because it lets you control when that code is evaluated. The code below shows how a closure delays evaluation.

var customersInLine = [“Chris”, “Alex”, “Ewa”, “Barry”, “Daniella”]

print(customersInLine.count)     // Prints “5”

let customerProvider = { customersInLine.remove(at: 0) }

print(customersInLine.count)      // Prints “5”

print(“Now serving \(customerProvider())!”)   // Prints “Now serving Chris!”

print(customersInLine.count)      // Prints “4”

Even though the first element of the customersInLine array is removed by the code inside the closure, the array element isn’t removed until the closure is actually called. If the closure is never called, the expression inside the closure is never evaluated, which means the array element is never removed. Note that the type of customerProvider is not String but () -> String—a function with no parameters that returns a string.

You get the same behavior of delayed evaluation when you pass a closure as an argument to a function.

// customersInLine is [“Alex”, “Ewa”, “Barry”, “Daniella”]

func serve(customer customerProvider: () -> ) {

    print(“Now serving \(customerProvider())!”)

}

serve(customer: { customersInLine.remove(at: 0) } )

// Prints “Now serving Alex!”

The serve(customer:) function in the listing above takes an explicit closure that returns a customer’s name. The version of serve(customer:) below performs the same operation but, instead of taking an explicit closure, it takes an autoclosure by marking its parameter’s type with the @autoclosure attribute. Now you can call the function as if it took a String argument instead of a closure. The argument is automatically converted to a closure, because the customerProvider parameter’s type is marked with the @autoclosure attribute.

// customersInLine is [“Ewa”, “Barry”, “Daniella”]

func serve(customer customerProvider: @autoclosure () -> ) {

    print(“Now serving \(customerProvider())!”)

}

serve(customer: customersInLine.remove(at: 0))

// Prints “Now serving Ewa!”

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

If you want an autoclosure that is allowed to escape, use both the @autoclosure and @escaping attributes. The @escaping attribute is described above in Escaping Closures.

classboxstart // customersInLine is [“Barry”, “Daniella”]

var customerProviders: [() -> ] = []

func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> ) {

    customerProviders.append(customerProvider)

}

collectCustomerProviders(customersInLine.remove(at: 0))

collectCustomerProviders(customersInLine.remove(at: 0))

print(“Collected \(customerProviders.count) closures.”)

// Prints “Collected 2 closures.”

for customerProvider in customerProviders {

    print(“Now serving \(customerProvider())!”)

}

// Prints “Now serving Barry!”

// Prints “Now serving Daniella!” classbox

In the code above, instead of calling the closure passed to it as its customerProvider argument, the collectCustomerProviders(_:) function appends the closure to the customerProviders array. The array is declared outside the scope of the function, which means the closures in the array can be executed after the function returns. As a result, the value of the customerProvider argument must be allowed to escape the function’s scope.

This Is A Custom Widget

This Sliding Bar can be switched on or off in theme options, and can take any widget you throw at it or even fill it with your custom HTML Code. Its perfect for grabbing the attention of your viewers. Choose between 1, 2, 3 or 4 columns, set the background color, widget divider color, activate transparency, a top border or fully disable it on desktop and mobile.

This Is A Custom Widget

This Sliding Bar can be switched on or off in theme options, and can take any widget you throw at it or even fill it with your custom HTML Code. Its perfect for grabbing the attention of your viewers. Choose between 1, 2, 3 or 4 columns, set the background color, widget divider color, activate transparency, a top border or fully disable it on desktop and mobile.