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.
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.
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 asguard 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.
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?
