TLDR: calling a method on nil
will crash. Variables that can be nil
are called Optional, and are defined using a question mark. To call a method on an optional variable, unwrap it by using a question mark (optional chaining), an exclamation point (force unwrapping), or an “if let” or “guard let” statement (conditional unwrapping).
nil
is ubiquitous in iOS and Swift code, so knowing what it is, what it does, and how to use it is very important.
nil
In Swift, nil
means: nothing is here. Specifically, it means that the variable which is nil
is unset. There is no value, it has not been initialized.
What happens when you try to call a function on nil
? A crash. Crashes are bad.
Optionals
Optionals help us avoid those crashes. Optionals tell Swift (or rather, the Swift compiler) that the variable could be unset (that is, it could be nil
).
Optionals are defined with a question mark, like so:
var name: String? = "Elliot"
That line defines a variable called name
, whose type is an optional String
, and whose value (currently) is "Elliot"
. Later on in your code, you might unset this variable by setting it equal to nil
, like this:
name = nil
Optional chaining
So, since that variable could be nil
, the compiler will refuse to let you call a method on it directly. This is where optional chaining comes in. Optional chaining is basically a way to tell Swift to check if the variable is nil
first before calling the method. You can do so by putting a question mark before calling the method; so, for instance, if you wanted to get the first initial of name
, you could do this:
name?.prefix(1)
Force unwrapping
Alternatively, if you know that the variable is NOT nil
at the point at which you’re calling the method, you can use an exclamation point instead:
name!.prefix(1)
which is called force unwrapping. This is dangerous, though, as if name is nil
, your app will crash.
Conditional unwrapping
But what happens if you want to set a non-optional variable with an optional value? Something like this:
var definitelyAName: String = name
This will fail to compile! Swift knows name could be nil
, so it won’t let you assign a non-optional variable with it. You could force unwrap as before:
var definitelyAName: String = name!
but it’s better to use conditional unwrapping instead, like so:
if let unwrappedName = name { var definitelyAName: String = unwrappedName }
This if let
statement tells Swift: if name
is not nil
, assign it to a let
constant called unwrappedName
(whose type will be a non-optional String
). Then, within the if, you can do what you need to with it.
A variation on this is guard let
. It works similarly to if let
, but it allows you to use the unwrapped variable for the rest of the current scope (the function, method, loop, or conditional you’re in). Here’s an example:
guard let unwrappedName = name else { fatalError("oh noes!") } var definitelyAName: String = unwrappedName
As you can see, you have to provide guard
with an else
case, so that it has something to do if name
is nil
.
Nil coalescing
Finally, you could give the variable a fallback value in case name
is nil
, like so:
var definitelyAName: String = name ?? ""
The double question mark is called the nil coalescing
operator, and its job is to provide that fallback value.