防范具有 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 可选值的开关按钮的主要内容,如果未能解决你的问题,请参考以下文章

Nil 同时展开一个实际具有值的可选

Swift-不断收到“致命错误:在展开可选值时意外发现 nil”

prepareForSegue 出错“”在展开可选值时意外发现 nil“”

在展开可选值 uitextfield 时意外发现 nil

致命错误:在展开可选值 UIPageViewController 时意外发现 nil

使一个按钮具有开关二项功能,用basic语言如何实现?