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

Optionals

The value that may be missing, the question mark that says so, and the safe ways to open, guard and replace a missing value.

Part 7 of 12

Intermediate17 min readBack to Courses

Some answers really are missing

A search may find nothing. A lookup may have no match. Swift writes that possibility into the type: String is text, and String? is text that may also be absent, where the question mark means the value might be nil.

The compiler will not let you use a String? as ordinary text. It insists you deal with the missing case first, which turns a common crash into a message on the line that caused it.

Underneath, an optional is an enum with two cases: one that holds a value and one that holds nothing. String? is shorthand for Optional<String>, and nil is the empty case. That is why printing an optional shows Optional("Ada"): you are seeing the case, not just the text inside it.

Opening it safely with if let

The if let form opens an optional only when there is something inside. You give the value a fresh name, and the block runs just in the case where a value was there.

Add an else for the missing case. Nothing is forced, nothing crashes, and both answers are written down where a reader can see them.

The new name can be the same as the old one: if let name = name is idiomatic and shadows the optional for the length of the block. Inside the braces name is a plain String; outside, the optional is unchanged. That shadowing keeps the safe value close to the check instead of inventing a second name for every optional.

guard, the fallback, and the last resort

Inside a function, guard let opens a value and continues only when it exists. When it does not, the else block must leave the function, usually with return, which keeps the main path of the code flat.

The ?? operator supplies a fallback in one expression, such as name ?? "no name". The exclamation mark forces an optional open and is a promise that a value is there. When the promise is wrong the program stops, so reach for it last.

The else of a guard must leave the current scope, which usually means return, break or continue. The compiler enforces that, because a guard that could fall through would leave the value unopened. ?? is lazy: the fallback expression runs only when the left side is nil, so an expensive default is not built for nothing.

Chaining through a maybe

When a value may be missing, every step that depends on it is also a maybe. Optional chaining writes that in one line: person?.name gives a String?, and the whole expression is nil when person is nil, without a crash.

A chain can end with ?? to supply a fallback for the whole expression, such as person?.name ?? "unknown". The fallback is used only when some link in the chain was missing.

A chain may include methods and subscripts, not only properties. person?.names.first?.uppercased() gives a String? even though uppercased() returns a plain String, because any link may be missing. The chain stops at the first nil and the whole expression becomes nil, without running the rest.

What goes wrong

A forced unwrap fails at run time with a message naming the line: “Unexpectedly found nil while unwrapping an Optional value”. The compiler accepted the promise, so there is no warning before it happens. Treat every ! as a place to revisit when the input changes, because that is where a new empty case will surface.

An if let with no else is not wrong, but it hides the missing case from the reader. If nothing happening is a real outcome, say so in an else; if it is impossible, a guard at the top of the function makes that claim explicit. A dictionary lookup and first both return optionals for the same reason: the answer may genuinely not exist.

Four ways to face a maybe

func role(of name: String) -> String? {
    return name == "Ada" ? "math" : nil
}

let known = role(of: "Ada")

if let value = known {
    print("Found:", value)
}

func show(_ name: String?) {
    guard let name = name else {
        print("No name")
        return
    }
    print("Hello,", name)
}

Three habits keep optionals safe. The exclamation mark forces a value out without a check, so a wrong promise stops the program; prefer if let, guard let or ??. An if let block is skipped when the value is missing, so write the missing case in else when the reader needs to see it. And a dictionary lookup, first, and a failed conversion all return optionals, which must be opened before they act like plain values.

A role that may not exist

Run it and watch what happens when there is no role. Then change the function so Alan has a role too, and predict which printed lines change before you run again.

Output
Click "Run" to execute your code

Try these next

  • Look up a key that is not in a dictionary and print a fallback with ??.
  • Write a function that returns Int? and call it with one valid and one invalid input.
  • Rewrite a forced unwrap as if let, then as guard let, and compare the two shapes.

Nicknames, with a missing case

Run it and read how each name is treated. Then add a nickname for Alan and predict which printed lines change before you run it again.

Output
Click "Run" to execute your code

The exclamation mark is a promise the compiler cannot check. Every forced value is a place the program could stop, so prefer if let, guard let or a ?? fallback unless you are certain.

Check what you learned

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

Part 1 of 5

What does the question mark in String? mean?