Swift good coding practice: If statement with opti

2019-02-12 13:58发布

问题:

So I've been developing an app in Swift, and today I spent nearly an hour debugging a problem that turned out to be completely unexpected. It all resulted from the code below.

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

}

The problem was that this if statement ALWAYS returned true. So I thought that maybe I was setting isAI to true somewhere but in the end I realized that I declared isAI as an optional type as shown below.

var isAI: Bool!

when it should have been

var isAI: Bool

This resulted in the if-statement not checking if isAI was true, but instead checking if it contained a value.

So to be safe now I make sure to write my if-statments like this

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

}

So my question is, what are my options to avoid this problem in the future? (this problem seems extremely dangerous, especially when working on a team on a large project). Should I always write my if-statment explicitly, should I just avoid the optional type for Bools altogether?

Note that I did not have this problem in Xcode Beta 2. This problem came about when I upgraded to Xcode beta 3. I think because in Beta 2 Apple handled implicitly unwrapped Bool in an if-statement by checking its value rather than checking if it contains a value.

Lastly, below is an example of which if-statements run given an optional Bool to better help people understand the problem.

let myBool: Bool! = false

if (myBool) {
    //Runs
}

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

if (!myBool) {
    //Runs
}

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

回答1:

This is a known issue that is being tracked on the SwiftInFlux repo, which includes this quote from Chris Lattner on the Apple developer forums.

This problem exists with any optional of something that conforms to the LogicValue protocol (e.g. nested optionals, optional of bool, etc). We consider it serious issue that needs to be fixed for 1.0 and have some ideas, but haven't settled on a solution yet.

So, this issue doesn't just effect optional Bools, but any optional type that conforms to the LogicValue protocol (defined as).

protocol LogicValue {
    func getLogicValue() -> Bool
}

Anyway as far as recommendations on how to work around this go, it's hard to recommend any one specific solution considering that Apple hasn't given an indication of how they intend to solve this in the future, but I would imagine that continuing to explicitly check the value of the Bool would be the way to go.

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

In fact, after some further reading, the quote listed above continues to read:

For this common case, the simplest answer would be to produce a warning for "if x" and require someone to explictly write "if x != nil" or "if x == true" to make it explicit what they want.



回答2:

my advice is to use this nice coalescing ??

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


回答3:

If the bool is part if Core Data (aka NSNumber), you should do it like this.

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

Regards