问题 Swift良好的编码实践:如果语句带有可选类型Bool


所以我一直在Swift中开发一个应用程序,今天我花了近一个小时来调试一个完全出乎意料的问题。这一切都来自下面的代码。

if (hero.isAI) { //isAI is a Bool

}

问题是这个if语句总是返回true。所以我想也许我在某处将isAI设置为true但最后我意识到我将isAI声明为可选类型,如下所示。

var isAI: Bool!

什么时候应该

var isAI: Bool

这导致if语句不检查isAI是否为真,而是检查它是否包含值。

所以为了安全起见,我确保写下这样的if-statments

if (hero.isAI == true) { //isAI is a Bool

}

所以我的问题是, 有什么方法可以避免将来出现这个问题? (这个问题似乎非常危险,特别是在大型项目团队工作时)。 我是否应该明确地写出我的if-statment,我应该完全避免Bools的可选类型吗?

请注意,我在Xcode Beta 2中没有遇到此问题。当我升级到Xcode beta 3时出现了这个问题。我认为因为在Beta 2中Apple通过检查其值而不是检查它是否在if语句中处理了隐式解包的Bool包含一个值。

最后,下面是一个示例,其中if-statements运行给定一个可选的Bool,以更好地帮助人们理解问题。

let myBool: Bool! = false

if (myBool) {
    //Runs
}

if (myBool!) {
    //Won't Run
}

if (!myBool) {
    //Runs
}

if (myBool == true) {
    //Won't Run
}

7259
2017-07-19 17:03


起源

为什么你首先有一个可选的bool?容易避免吗? - jtbandes
我有一个初始化后运行的安装方法。 - Epic Byte
对不起,我对选项有点困惑,为什么呢 ! 并不是 ?什么时候宣布呢? - domshyra
我选择将Bool声明为隐式展开,以便每次我想使用它时都不需要打开它。而且因为我知道我会给它分配一个值。通常我根本不需要使它成为可选项,只需在初始化时为其分配一个值,但我有一个单独的设置方法,它在初始化之后发生,因此Bool在设置方法运行之前在技术上将是nil。 - Epic Byte
包装Bools的问题已在较新的Swift版本中得到修复。要检查可选项是否为零,现在最多将其与nil进行比较。所以没有重复的含义了。 - gnasher729


答案:


这是一个已知的问题,正在跟踪 SwiftInFlux repo,其中包含此引用 Chris Lattner在Apple开发者论坛上

任何符合的选项都存在此问题   LogicValue协议(例如嵌套的选项,可选的bool,   等等)。我们认为这个问题需要针对1.0和1.0进行修复   有一些想法,但还没有解决方案。

因此,此问题不仅会影响可选的Bools,还会影响符合LogicValue协议(定义为)的任何可选类型。

protocol LogicValue {
    func getLogicValue() -> Bool
}

无论如何,就如何解决这个问题的建议而言,考虑到Apple未在未来如何解决这个问题,很难推荐任何一个特定的解决方案,但我想会继续明确检查Bool的价值将是最佳选择。

if (hero.isAI == true) {
    // stuff    
}

事实上,在进一步阅读之后,上面列出的引用仍然是:

对于这种常见情况,最简单的答案是产生一个   警告“if x”并要求某人明确写“如果x!=   nil“或”如果x == true“使其明确表达他们想要的东西。


11
2017-07-19 17:49



谢谢你,正是我所寻找的。很高兴看到他们承认这是一个问题。 - Epic Byte


我的建议是使用这个漂亮的合并 ??

if textfieldDate.text?.isEmpty ?? true {
    // the text is either nil or empty but its all we want to know
}

3
2017-11-10 11:49





如果bool是Core Data(又名NSNumber)的一部分,你应该这样做。

if (isHero.isAI?.boolValue != nil)

问候


0
2018-05-05 18:55