Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

array
An ordered list of values of one type, reached by position starting at zero.
block
A group of lines of code that run together, often inside curly brackets.
closure
A piece of code you can store in a value and pass to other code, remembered with the names around it.
compiler
The program that turns the code you write into something the machine can run, reporting mistakes before it does.
dictionary
A collection of key and value pairs, where each key appears once and finds its value.
enum
A type whose value is one of a fixed set of named cases, which may each carry extra data.
expression
A piece of code that produces a value, such as a sum or a call to a function.
function
A named piece of code that takes values and returns a result when called.
guard
A check that must pass before the code after it runs, leaving the scope early when it fails.
method
A function that belongs to a type and is called on a value of that type.
nil
The absence of a value, allowed only where a type says a value may be missing.
operator
A symbol such as plus or equals that combines values into a new one.
optional
A type that either holds a value or holds nothing, written with a question mark after the type.
optional chaining
Writing a question mark before something you reach into, so the result is nil when the value is missing.
property
A named value that belongs to a type or to one of its values.
protocol
A list of requirements that a type promises to meet, so code can work with any type that meets them.
scope
The region of code where a name can be used before it goes out of reach.
string interpolation
Putting a value inside text with a backslash and parentheses, so the value becomes part of the text.
struct
A type that groups related values and makes a copy whenever it is given another name or passed along.
subscript
A way to read or write an item in an array or dictionary by putting a key or position in square brackets.
type
What kind of value something is, such as a whole number or text, and what it can do.
unwrap
To get the value out of an optional after checking that something is there.

Swift from the ground up

Loops and ranges

Repeating work with for-in, counting with ranges, and looping while a condition still holds.

Part 5 of 12

Intermediate15 min readBack to Courses

Repeat without copying

A for in loop walks through a collection one item at a time. You name the item, and the block between the braces runs once for each value.

This is how you write one line that handles a list of any length. Copying the same line ten times would break the moment the list changed size.

The loop variable is a copy of the item, not a way to change the collection. Assigning to name inside the block changes only that pass; the array keeps its original values. When a loop must change the array, iterate over its indices or build a new array instead, because changing a collection while walking it is the source of many confusing results.

Counting with ranges

A range gives you the numbers themselves. 1...3 counts one, two, three, with both ends included. 1..<3 counts one and two, leaving the last number out.

When the number in the range is not needed, name it with a single underscore so the reader knows the value is deliberately ignored.

A range is a value in its own right, so 1...3 can be stored and passed around. reversed() turns one around without changing it, and stride handles a step that is not one. for i in (1...3).reversed() counts three, two, one, which is clearer than subtracting from a bound inside the block.

while, and doing it once at least

A while loop repeats while a condition stays true, which is the right tool when you do not know the count in advance. Something inside the block must move the condition toward false, or the loop never ends.

The repeat form runs the block first and checks the condition after. That is how you guarantee the body runs at least once.

The condition of a while is checked before every pass, including the first. If it is false at the start, the body never runs at all. A while true loop therefore needs a break somewhere inside; the compiler will not warn you, because a loop that leaves through a break is perfectly legal.

Three kinds of loop

let names = ["Ada", "Alan"]

for name in names {
    print("Hello,", name)
}

for i in 1...3 {
    print("Step", i)
}

var n = 3
while n > 0 {
    print("Left", n)
    n -= 1
}

repeat {
    print("runs at least once")
} while false

Stride, continue and labels

stride(from:to:by:) walks numbers by a step other than one: stride(from: 10, to: 0, by: -2) counts down in twos, and the to value is excluded. through: includes the final value. It is the tool for every count that is not a simple range.

continue skips the rest of the current pass, and break leaves the loop. A label before the loop lets an inner break leave the outer one too: outer: for … { for … { break outer } }. Labels are rare, but they are clearer than a flag when a nested search is done.

continue does not skip the loop’s own bookkeeping. In a for loop it jumps to the next item, and in a while loop it jumps back to the condition, so any update below the continue is skipped. That is the usual bug: a counter incremented at the bottom of the block never moves when the skipped branch is taken.

Three dots (1...3) includes three; two dots and a less-than (1..<3) stops at two. Mixing them up is the usual off-by-one. A while loop needs the same care: something inside must move the condition toward false.

Loops are not the only tool

Swift’s collections also answer questions directly: map transforms every item, filter keeps the ones that pass, and reduce folds them into one value. A loop is still the right tool when the work is a sequence of side effects, but when the goal is a new collection, the method says it in one line and removes the index arithmetic.

Use the method when you want a new value; use the loop when each pass must do something to the outside world.

Chained methods read from left to right, but each one produces a whole new array before the next starts. For a list of a few dozen scores that is irrelevant; for a very large list it is worth knowing that a loop with one accumulator can do the same work without the intermediate copies.

Try these next

  • Print every other number from 1 to 9 with stride(from: 1, through: 9, by: 2).
  • Use continue to skip one name in the greeting loop.
  • Rewrite the countdown with stride and no while.

Greetings, steps and a countdown

Run it and follow the order of the lines. Then change the countdown start to five and predict how many count lines print.

Output
Click "Run" to execute your code

A stride and a labelled break

Run it, then change the stride step to -3 and predict the countdown before running it again.

Output
Click "Run" to execute your code

A loop that never ends is the most common mistake here. Check that every value used in the condition changes somewhere inside the block, so the loop can reach its end.

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

What does for name in names do?