防范具有 nil 可选值的开关按钮
Posted
技术标签:
【中文标题】防范具有 nil 可选值的开关按钮【英文标题】:Guarding against a switch button having a nil optional value 【发布时间】:2016-09-19 19:28:39 【问题描述】:如果在设置中设置了如下开关,我有一段代码会运行:
UserDefaults.standard.bool(forKey: "signatureSwitchState")
let buttonState = UserDefaults.standard.object(forKey: "signatureSwitchState") as! Bool
if buttonState == true
sign()
我的问题是,如果开关从未被激活,程序将失败,因为编译器指出“致命错误:在展开可选值时意外发现 nil”
然后我的问题是,在使用诸如上述语句中的 switch 之类的 bool 时,如何最好地防止出现 nil 值。
我尝试过 if let 语句和 guard 语句,但编译器抱怨这些不能与 bool 一起使用。
【问题讨论】:
What does "fatal error: unexpectedly found nil while unwrapping an Optional value" mean?的可能重复 【参考方案1】:你应该使用:
let buttonState = UserDefaults.standard.bool(forKey: "signatureSwitchState")
如果没有显式设置值,则返回 false。
【讨论】:
【参考方案2】:如果您尝试从 UserDefaults 中获取布尔值,您可以使用
let buttonState = UserDefaults.standard.bool(forKey: "signatureSwitchState")
,
这个函数返回一个布尔值,所以你知道该值只能是真或假,如果它没有找到键的值,那么它将返回假。您正在使用的功能
UserDefaults.standard.object(forKey: "signatureSwitchState")
返回一个 AnyObject?所以它可以为零。
【讨论】:
【参考方案3】:鲜为人知,但 Apple 强烈推荐:
注册默认值,直到用户第一次更改该值。
在applicationDidFinishLaunching
中——至少在第一次访问值之前——注册键/值对。
let userDefaults = UserDefaults.standard
let defaultValues : [String : Any] = ["signatureSwitchState" : false]
userDefaults.register(defaults: defaultValues)
现在值永远不会是nil
(我知道Bool
的例子很弱)
let buttonState = UserDefaults.standard.bool(forKey: "signatureSwitchState")
对象比“原始”类型更能利用这种方式,因为“原始”类型从来都不是nil
。
【讨论】:
【参考方案4】:我有一个提示可能会在未来派上用场,尽管它不如picciano 的answer 好,这绝对是正确的方法。
UserDefaults.standard.object(forKey: "signatureSwitchState")
返回一个AnyObject
。
如果您尝试强制转换为Bool
(as! Bool
),如果返回值不是Bool
,或者如果它不是nil
,这将崩溃。相反,如果您有条件地转换 (as? Bool
),您将收到 Bool?
。这会将值转换为 Bool
(如果存在),否则会为您提供 nil
(不会崩溃。
从那里,您可以使用 nil 合并运算符 (??
) 将此 Bool?
转换为 Bool
。如果有Bool
值,它将返回您,否则将返回您提供的默认值。在这种情况下,false
。
另外,因为buttonState
已经是Bool
,所以没有理由在if
语句中将其与true
进行比较。直接使用即可:
let buttonState = UserDefaults.standard.object(forKey: "signatureSwitchState") as? Bool ?? false
if buttonState
sign()
【讨论】:
【参考方案5】:有几种方法可以做到这一点。由于这是一个布尔值,因此使用 nil-coalescing ??
可能是最简单的:
let buttonState = UserDefaults.standard.object(forKey: "signatureSwitchState") as? Bool ?? false
或者,您可以使用guard
来执行此操作,这可能更健壮:
guard let buttonState = UserDefaults.standard.object(forKey: "signatureSwitchState") as? Bool else return
if buttonState == true
sign()
请注意,在这两种情况下,您都必须将强制展开 (!
) 更改为可选展开 (?
)。
【讨论】:
以上是关于防范具有 nil 可选值的开关按钮的主要内容,如果未能解决你的问题,请参考以下文章
Swift-不断收到“致命错误:在展开可选值时意外发现 nil”
prepareForSegue 出错“”在展开可选值时意外发现 nil“”