当我到达包含此代码的页面时:
override func viewDidLoad() {
super.viewDidLoad()
//Load Upgrades
let FourthDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
var upgrades = FourthDefaults.valueForKey("Upgrades")?.integerValue
FourthDefaults.synchronize()
Upgrades = upgrades!
}
我收到了一个EXC_BAD_INSTRUCTIONS错误:
Upgrades = upgrades!
如果这有帮助,这是我的保存方法。
let FourthDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
FourthDefaults.setObject(Upgrades, forKey: "Upgrades")
FourthDefaults.synchronize()
额外信息:只有在我保存之前加载此代码才会发生这种情况。否则它工作正常。
如果您知道如何解决此问题,请回复。谢谢!
答案 0 :(得分:1)
valueForKey
返回一个可选项。如果密钥“升级”没有值,则结果为nil
。在您第一次保存值之前就是这种情况。
这就是你必须写valueForKey("Upgrades")?.integerValue
的原因 - 因为如果返回的值是nil
而不是AnyObject
,则无法在其上调用.integerValue
。您必须使用?.
运算符。将该运算符读为“如果结果为nil
,则停止并返回nil
,否则继续并返回包含下一个方法结果的可选项。”
因此upgrades
是nil
(如果没有这样的密钥),或者是包含所需值的可选项。
如果使用!
强制解包可选项,并且它是nil
,您将获得运行时断言,就像您正在获取的那样。因此,您几乎不应该使用!
。您需要使用它的时间非常少见,您应该仔细考虑是否有替代方案。
在这种情况下,有一个更好的选择 - 使用??
运算符:
var upgrades = FourthDefaults.valueForKey("Upgrades")?.integerValue ?? 0
(或者在缺少密钥的情况下你想要的任何默认值,如果0
不是它)
??
读作:如果左边的表达式为nil
,则替换右边的值。否则,请使用左侧的展开值。
这样做的好处是不再需要!
,并且应该消除运行时错误。
或者,如果您想在尚未设置值时执行不同的代码,可以这样写:
if let upgrades = FourthDefaults.valueForKey("Upgrades")?.integerValue {
// use upgrades, which will be unwrapped in this block
}
else {
// handle the value not being set yet
}
有关选项有用的原因,请尝试阅读this answer。