valueForKey
returns an optional. If there is no value for the key “upgrades”, the result will be nil
. This will be the case before you save the value for the first time.
This is why you have to write valueForKey("Upgrades")?.integerValue
– because if the value returned is nil
instead of an AnyObject
, you can’t call .integerValue
on it. You have to use the ?.
operator. Read that operator as “if the result of this is nil
, then stop and return nil
, otherwise continue and return an optional containing the result of the next method.”
So upgrades
is either nil
(if there was no such key), or an optional containing the value you want.
If you force-unwrap an optional using !
, and it is nil
, you will get a runtime assertion, like you’re getting. For this reason you should hardly ever use !
. The times you do need to use it are pretty rare and you should think carefully about whether there’s an alternative.
In this case there is a much better alternative – use the ??
operator:
var upgrades = FourthDefaults.valueForKey("Upgrades")?.integerValue ?? 0
(or whatever default value you want in the case of a missing key, if 0
isn’t it)
The ??
reads as: if the expression on the left is nil
, then substitute the value on the right instead. Otherwise, use the unwrapped value on the left.
This has the benefit of you not needing the !
anymore, and should eliminate your runtime error.
Alternatively, if you want to execute different code when the value hasn’t already been set, you could write this:
if let upgrades = FourthDefaults.valueForKey("Upgrades")?.integerValue {
// use upgrades, which will be unwrapped in this block
}
else {
// handle the value not being set yet
}
For more on why optionals are useful, try reading this answer.