The question mark operator signifies optionality in Swift.
You can declare many things a optional, meaning they could be nil
or hold a value. This includes for example variable declarations
, computed properties
, return values of functions
and callbacks/closures
. Also certain operations like casting or retrieving values from dictionaries will yield optional values.
When you want to use the value contained you have to unwrap them, cause there might not be one and the may be pointing to nil
. There are many ways and forms of unwrapping and optionality chaining.
Explaing your particular examples:
In a dictionary retrieving a stored value via a key as in myDict[myKey]
returns an optional value. The value for the key stored within your specific dictionary is another dictionary. By declaring transitions[state]?[transition]
you say basically "if there is a dictionary found for the key state
, go ahead and continue with this dictionary and get the value for the key transition
for that dictionary, otherwise use nil".
This code:
return transitions[state]?[transition] != nil
is basically a shorter way of writing this:
if let stateDict = transitions[state] {
return stateDict[transition] != nil
} else {
return false
}
Your other example is about an optional closure passed into a function. You can also pass optional closures into functions and call them via closure?()
. The ?
signifies that if nil is passed for the closure, nothing should be done, otherwise it should be executed.
This code:
observe?(prev, next)
is basically a shorter way of writing this:
if let observeClosure = observe {
observeClosure(prev, next)
}
Some more optionality explanations:
If you work with an optional value from a declared variable you can safely unwrap it like so:
func square(myValue: Int?) → Int {
guard let myValue = myValue else {
return 0
}
return myValue * myValue
}
or
func square(myValue: Int?) → Int {
if let myValue = myValue {
return myValue * myValue
} else {
return 0
}
}
or you could define a fallback with the ??
operator
func square(myValue: Int?) → Int {
return myValue ?? 0 * myValue ?? 0
}
You could also use the !
operator to unwrap unsafely and if nil
is found your app would crash. You should never do that unless you can guarantee that nil
cannot be found like in:
func square(myValue: Int?) → Int {
if myValue != nil {
myValue! * mayValue! {
} else {
return 0
}
}