How to compare @NO and @YES with elegance and without risk of false positives/negatives?

11,894

Solution 1

What is condition? Is it a BOOL or an NSNumber?


If condition is a BOOL, then you don't want to use @NO or @YES at all. You want to say

if (condition) // test if condition is true

if (!condition) // test if condition is false

if (condition == NO) // same as previous, based on personal preference

Note that you should never say

if (condition == YES)

because BOOL isn't actually restricted to 0 and 1 as values, it can hold anything in char, so if condition accidentally holds, say, 3, then if (condition) and if (condition == YES) would behave differently.


If condition is an NSNumber, then you still don't want to use @NO and @YES. You just want to convert it to a BOOL using -boolValue, as in

if ([condition boolValue]) // test if condition is true

if (![condition boolValue]) // test if condition is false

if ([condition boolValue] == NO) // same as previous, based on personal preference

The basic takeaway here is, don't use @NO and @YES literals for comparisons. It's pointless, and inelegant, since all you'd be able to do with them is convert them back into BOOLs.

Solution 2

Assuming the data type of condition is BOOL, then you want:

if (condition) {
    // true (YES)
} else {
    // false (NO)
}

If condition is an NSNumber then use:

if ([condition boolValue]) {
    // true (YES)
} else {
    // false (NO)
}

If condition is based on some arbitrary numbers then treat 0 as NO and treat non-zero as YES.

Again, if condition is an NSNumber then do:

if ([condition intValue]) {
    // non-zero - true (YES)
} else {
    // zero - false (NO)
}

Update: Based on the following comment from the OP:

Condition is a bool, like if (myView.frame.size.height == 30)

This implies that the actual question wanted to do checks something like:

if ((myView.frame.size.height == 30) == YES)

This is very unusual. The proper thing to do is:

if (myView.frame.size.height == 30) {
    // true - height is 30
} else {
    // false - height is not 30
}

There is no need to worry about false positives or negatives. The condition is either true or it isn't. There is no 3rd possibility. If the condition gives the wrong result then the solution is to fix the condition.

Solution 3

You can save @NO in a dictionary because @NO is an object. You cannot save NO in a dictionary. So use @NO.boolValue when needed. For example:

NSDictionary *userSetting = (NSDictionary *)[[NSUserDefaults standardUserDefaults] objectForKey:@"user"];
//Suppose you have done: userSetting[@"canWriteCode"] = @YES;
if ([userSetting[@"canWriteCode"] boolValue])
    [self helloProgrammer];
Share:
11,894
zakdances
Author by

zakdances

Updated on June 06, 2022

Comments

  • zakdances
    zakdances almost 2 years

    I want to use bool literals like

    if (condition == @NO) {
    
    }
    else if (condition == @YES) {
    
    {
    

    When I try this, XCode wants me to use NSNumber methods to compare, like isEqualTo. Is there a simpler way to do this (without isEqualTo)? If I can't, should I use isEqualTo, isEqualToValue, or isEqualToNumber?

  • zakdances
    zakdances about 11 years
    What numbers trigger @NO or @YES?
  • rmaddy
    rmaddy about 11 years
    None directly. If condition is created from [NSNumber numberWithBool:] then you compare against @YES or @NO.
  • Carl Veazey
    Carl Veazey about 11 years
    Comparing to YES may be problematic in some cases. And +1 for not using dot syntax for a non-property method call.
  • rmaddy
    rmaddy about 11 years
    @yourfriendzak Notice all of the options. This is because you haven't been clear. What type is condition? How have you created its value?
  • rmaddy
    rmaddy about 11 years
    @CarlVeazey Yes, until we get more details about the type of condition and how its value is set, it's difficult to nail down the proper solution.
  • rmaddy
    rmaddy about 11 years
    I don't know why this was downvoted. If condition is an NSNumber and the OP doesn't want to use isEqual:, then this is actually one possible solution.
  • Lily Ballard
    Lily Ballard about 11 years
    A few bad answers in here. Never ever say condition == YES, because BOOL isn't a true boolean value and therefore may have a non-zero value that's not the same as YES. Similarly [condition isEqual:@YES] would only work if condition was constructed from YES to begin with; if it's a non-zero non-YES value, that will also fail. And of course [condition boolValue] == YES is also bad.
  • rmaddy
    rmaddy about 11 years
    @KevinBallard If BOOL values are only used with YES or NO then what I have is just fine. Personally, anyone that assigns any other value to a BOOL variable is asking for trouble (and it using it wrong). What I have posted will never be a problem in my own code because I only use the proper values with BOOL values.
  • rmaddy
    rmaddy about 11 years
    @KevinBallard Once the OP chimes in here and tells us what he really has, more precise answers can be given.
  • Lily Ballard
    Lily Ballard about 11 years
    @rmaddy: Regardless of what you do personally, it's a really bad idea to give out advice like this to other people. The simple fact is, if (boolValue == YES) is not the same thing as if (boolValue), with the former unexpectedly evaluating the condition to 0 in some cases.
  • Lily Ballard
    Lily Ballard about 11 years
    Why would you ever say @NO.boolValue instead of just saying NO?
  • rmaddy
    rmaddy about 11 years
    @KevinBallard I only use if (value) or if (!value) myself. Again, until the OP chimes in, my answer is tailored to the style of the original code.
  • Lily Ballard
    Lily Ballard about 11 years
    @rmaddy: It's still bad advice. Code that behaves correctly trumps matching style every time.
  • anticyclope
    anticyclope about 11 years
    > I want to use bool literals
  • rmaddy
    rmaddy about 11 years
    @KevinBallard Personally I wouldn't but it is valid.
  • zakdances
    zakdances about 11 years
    Condition is a bool, like if (myView.frame.size.height == 30)
  • rmaddy
    rmaddy about 11 years
    @yourfriendzak So condition isn't a variable of type BOOL or NSNumber? Now your question makes no sense. Why would you do something like if ((myView.frame.size.height == 30) == YES)? Is that what you are really asking?
  • zakdances
    zakdances about 11 years
    @rmaddy Yes, I wanted to evaluate nested expressions. Sorry for the confusion.
  • rmaddy
    rmaddy about 11 years
    @yourfriendzak Please see the update I added to the end of my original answer. Does this now answer your question?
  • Jelle
    Jelle about 11 years
    @maddy Valid yes, but just as pointless as converting NO to a string "nooohoooo" and parsing that string back to a BOOL, right?
  • zakdances
    zakdances about 11 years
    @rmaddy It's people like you that make SO such an amazing place.
  • borrrden
    borrrden about 11 years
    Note that !condition and condition == NO are not the same. There is one edge case. Let's say condition is 256. This would overflow into 0 and be equal to NO since it is simply a signed char. However, the ! operator returns a C boolean, which is explicitly defined by the C standard to be true for all values other than zero. So the BOOL would be NO and the bool would be true
  • anticyclope
    anticyclope about 11 years
    The OP wanted to use bool literals and I provide a solution. I don't see any actual reason for this answer to be downvoted, no matter how "pointless" it is, since it is answering the actual question. If you think the question was wrong, downvote the question instead.
  • borrrden
    borrrden about 11 years
    Nevermind about that, the above example seems to work itself. The case that bit me is slightly different. For certain cases of BOOL (namely the 8-bit overflow) (flag) and (flag == NO) will both be false.
  • HAS
    HAS about 11 years
    You can also use the Objective-C 2.0 notation for accessors for boolValue
  • Lily Ballard
    Lily Ballard about 11 years
    @borrrden: !flag and flag == NO are, by definition, identical.
  • borrrden
    borrrden about 11 years
    @KevinBallard Yes, you are correct, sorry that I wrote that but I've had trouble with BOOLs before and I thought it was related, but it wasn't. The case I had trouble with was when I expected a YES value (and for a bool it would have worked correctly) but instead I got a NO value. The solution was to either cast to bool or use !!condition (double not operator that implicitly casts to bool). I thought for sure it would be related to this but it turns out not to be.
  • Ríomhaire
    Ríomhaire over 9 years
    Remember that BOOLs are stored as NSNumbers in Core-Data
  • noamtm
    noamtm over 8 years
    @anticyclope I didn't personally downvote, I save downvoting for really bad answers. But I supposed you were downvoted because people want the answers here to be "correct" in the sense of "a good way to do it", and not just "technically correct yet somewhat pointless".