You can use Optional Chaining in order to call a method, access a property or subscript an optional. This is done by placing a ?
between the given optional variable and the given member (method, property or subscript).
struct Foo {
func doSomething() {
print("Hello World!")
}
}
var foo : Foo? = Foo()
foo?.doSomething() // prints "Hello World!" as foo is non-nil
If foo
contains a value, doSomething()
will be called on it. If foo
is nil
, then nothing bad will happen – the code will simply fail silently and continue executing.
var foo : Foo? = nil
foo?.doSomething() // will not be called as foo is nil
(This is similar behaviour to sending messages to nil
in Objective-C)
The reason that Optional Chaining is named as such is because ‘optionality’ will be propagated through the members you call/access. What this means is that the return values of any members used with optional chaining will be optional, regardless of whether they are typed as optional or not.
struct Foo {
var bar : Int
func doSomething() { ... }
}
let foo : Foo? = Foo(bar: 5)
print(foo?.bar) // Optional(5)
Here foo?.bar
is returning an Int?
even though bar
is non-optional, as foo
itself is optional.
As optionality is propagated, methods returning Void
will return Void?
when called with optional chaining. This can be useful in order to determine whether the method was called or not (and therefore if the optional has a value).
let foo : Foo? = Foo()
if foo?.doSomething() != nil {
print("foo is non-nil, and doSomething() was called")
} else {
print("foo is nil, therefore doSomething() wasn't called")
}
Here we’re comparing the Void?
return value with nil
in order to determine whether the method was called (and therefore whether foo
is non-nil).