After the branching structures if
and switch
, the most common structures you'll use in your programming are looping structures, which cause your program flow to execute the same code iteratively.
The looping structures you'll learn in this section are the following:
for…in
, which executes the same code a predetermined number of timeswhile
and repeat…while
, which executes code until a true condition becomes falseAs with the switch
control structure, there are many features and flexible options provided by these structures that make Swift more expressive and powerful than many other programming languages.
The following diagram illustrates how the for...in statement works:
Most programming languages have a for statement used to execute a code statement a certain number of times. The preceding diagram illustrates how the for...in statement works. A canonical example of a for loop in C, similar to many other C-inspired languages, is the following:
for(int i=0; i<10; i++) printf("i=%d\n", i);
The equivalent for
loop written in Swift is as follows:
for var i in 0..<10 { print(i) }
Comparing the two for
loops, they appear quite similar, but you could argue the Swift version is easier to read!
In Swift, a for…in
loop always iterates over a collection of values, rather than simply serving as a mechanism to count iterations. The range operator used in the preceding example returns a set of Int
values, which are then iterated over.
Internally, Swift creates an Iterator, then calls the next()
method of the Iterator until next()
returns nil, running the code block for each iteration.
Although the previous code example actually does iterate over Int
values, it's effectively running a code block a specific number of times. More often, you'll use for…in
to iterate over a collection of objects stored in your application.
The most common method to iterate over a set of objects is to use the for syntax, as in the following example:
let strings = ["First String", "Second String", "Third String", "Fourth String"] for obj in strings { print(obj) }
Using this syntax, the print
statement within the block is executed once for each object in the strings
array. Swift implicitly creates the constant variable obj for use within the block.
In the previous example, the obj
local variable is implicitly created as a constant (that is, let
).
While let
is the default behavior, you can instruct the for
loop to create a mutable variable by specifying var
in the for
loop declaration, as follows:
for var obj in strings { obj = "obj is: \(obj)" print(obj) }
The preceding example iterates over the strings array, providing each string to the execution block in a local variable named obj. Sometimes, the code may need to know the ordinal position of the object being processed. This can be accomplished by using the Array enumerated member function of the collection being iterated:
for (index, text) in strings.enumerated() { print("The object at index \(index) is \(text)") }
The next feature of the for
loop we'll learn is using the where clause to control which iterations are processed.
In the previous examples, the code always outputs all of the strings in the variable strings. We might want to only output strings meeting a certain test, for example, only strings beginning with the letter F:
One way to accomplish this requirement would be to rewrite the for loop as follows:
let strings = ["First String", "Second String", "Third String", "Fourth String"] for string in strings { if string.starts(with: "F") { print(string) } }
An even more concise way to write this code is to use the for
loop's where clause, as follows:
let strings = ["First String", "Second String", "Third String", "Fourth String"] for string in strings where string.starts(with: "F") { print(string) }
Like most C-inspired languages, Swift supports the use of the break
control transfer statement in for loops.
The break
statement has the effect of immediately transferring program flow to the statement following the for
loop, effectively skipping the remaining portion of the current iteration, and cancelling all remaining iterations.
In the following example, the code within the for
loop tests whether the current iteration's string begins with the letter T
. If so, the for loop is immediately exited:
let strings = ["First String", "Second String", "Third String", "Fourth String"] for string in strings { if string.starts(with: "T") { break } print(string) }
Swift also supports the use of the continue
control transfer statement in for
loops.
The continue
statement has the effect of skipping the remaining portion of the current iteration. Control then passes to the top of the for loop, where the next iteration proceeds (if there is a next iteration available).
In the following example, the continue
control transfer statement is used to skip any iteration having a string starting with the letter F
:
let strings = ["First String", "Second String", "Third String", "Fourth String"] for string in strings { if string.starts(with: "F") { continue } print(string) }
Swift provides a simple, expressive, and powerful for loop for
you to use in your programs. Key points to keep in mind regarding usage of the for loop are as follows:
for
always iterates over a collection of elements (and is not simply a counting variation of the while
loop as it is in some programming languages).enumerated()
as we did above). Use these methods to maintain simpler logic within your loops.for
loops support the break
and continue control transfer statements to provide flow control exceptions controlled by the code block they iterate over.Where the for
loop executes a code block a predetermined number of times, the while
loop continues executing a code block until a Boolean expression evaluates as false
. The preceding diagram illustrates how the while loop works.
The general syntax of the while
loop is as follows:
while {condition-list} { statements }
The syntax rules for the while
loop are essentially identical to that of the if
statement, specifically the following ones:
The while
statement supports the break
and continue
keywords to redirect flow control in the same manner as the for
loop.
The following example uses a while
loop to iterate over an array of Double
values to calculate an average for all prices less than seven (7):
let price:[Double] = [1.99, 2.99, 3.99, 4.99, 5.99, 6.99, 7.99, 8.99] var total = 0.0 var i = 0 while i < price.count && price[i] < 7.0 { i += 1 total += price[i] } print(total / Double(i)) // 5.49
Because it evaluates its condition(s) prior to the first iteration, a while loop
occasionally won't meet your needs. If you won't know whether a while loop should continue until after the first iteration, use the repeat…while
variant.
If you were developing a console application that should play a game until the user pressed Enter without entering text, a repeat…while loop would be the ideal solution. For example, the following Swift command-line program effectively uses repeat…while
where a while loop would be awkward:
#!/usr/bin/swift func playGame() { print("simulate gameplay") } repeat { playGame() print("enter q to quit") } while readLine() != "q"
This completes our look at the loops. Loops in Swift are important to implement the various program flow structures you might need to develop a variety of custom applications.
Loops and iteration are a core part of any computer program. Data is often stored in array and collection data structures, and loops allow you to develop concise, well-organized code to operate on them.
Use an Xcode playground to practice using the looping flow control structures we have covered in this section.
Loops.playground
.let provinces = ["Ontario", "Quebec", "Nova Scotia", "New Brunswick", "Manitoba", "British Columbia", "Prince Edward Island", "Saskatchewan", "Alberta", "Newfoundland and Labrador" ]
repeat…while
loop to print each of the provinces to the console:var i = 0 repeat { print(provinces[i]) i += 1 } while i < provinces.count-1 print("==============")
while
loop to print the same list of provinces to the console:i = 0 while i < provinces.count-1 { print(provinces[i]) i += 1 } print("==============")
for
loop to build a string containing the first letters of all provinces, and then print to the console as a sorted unique set of letters:var firstLetters = "" for province in provinces { firstLetters += province.prefix(1) } print("Canadian provinces start with one of the following letters: \(Set(firstLetters).sorted())")
for
loop with enumerated to determine the array indices of all provinces starting with the letter N
:var nProvinces = [Int]() for (index, province) in provinces.enumerated() { if province.prefix(1) == "N" { nProvinces.append(index) } } print("The indices of provinces starting with 'N' are: \(nProvinces)")