BOOL value in Dictionary

  • How does one get a boolean value from a dictionary object?
    My XML dictionary contains the value </true> under the given key.
    Should this be retrieved as NSNumber or some other object?

    I am trying to set the state of a checkbox button based on the value as
    below:

                // return syntax coloring switch
                BOOL *colorSwitch = NO;
                colorSwitch = [NSNumber numberWithBOOL:[temp
    objectForKey:@"BBLMColorsSyntax"]];
                NSLog(@"Color: %@", colorSwitch);
                if ( colorSwitch == YES) {
                    [colorBox setState:NSOnState];
                }
                else {
                    [colorBox setState:NSOffState];
                }
  • On Nov 21, 2008, at 7:48 AM, Richard S. French wrote:

    > How does one get a boolean value from a dictionary object?
    > My XML dictionary contains the value </true> under the given key.
    > Should this be retrieved as NSNumber or some other object?
    >
    > I am trying to set the state of a checkbox button based on the value
    > as
    > below:

    Lots of confusion here.

    >
    >
    > // return syntax coloring switch
    > BOOL *colorSwitch = NO;

    A BOOL is a scalar value.  It's not a class.  You don't typically
    declare a pointer to a BOOL for such simple purposes as you're using
    here.

    Even if you do declare a pointer-to-BOOL, initializing it with NO
    isn't doing what you think it is.  You don't have a false boolean
    value, you have a null pointer.

    > colorSwitch = [NSNumber numberWithBOOL:[temp
    > objectForKey:@"BBLMColorsSyntax"]];

    The subexpression [temp objectForKey:@"BBLMColorsSyntax"] already
    gives you an object.  If the object is what you think it is, then it's
    already an NSNumber, so there's no need to try to construct an
    NSNumber from it.

    Next, even if you did want to construct an NSNumber from it, it's not
    a BOOL.  So +numberWithBOOL: wouldn't be appropriate.  Any non-nil
    object pointer would result in a true-valued NSNumber, even if [temp
    objectForKey:@"BBLMColorsSyntax"] had given you a false-valued NSNumber.

    Third, you can't take the NSNumber which you're constructing (or
    retrieving with -objectForKey:) and assign it to colorSwitch, which is
    a pointer to BOOL, not a pointer to an object type.  Since colorSwitch
    ought not be a pointer, you definitely don't want to do that.

    > NSLog(@"Color: %@", colorSwitch);

    Again, colorSwitch isn't an object pointer, so %@ isn't an appropriate
    format specifier for it.

    > if ( colorSwitch == YES) {

    As colorSwitch is a pointer-to-BOOL rather than a BOOL, testing it for
    equality to YES won't do what you want.

    Even if colorSwitch were a BOOL rather than a pointer, your boolean
    test should probably not compare for equality to YES.  Just test the
    value of colorSwitch as the conditional (no comparison necessary).

    >
    > [colorBox setState:NSOnState];
    > }
    > else {
    > [colorBox setState:NSOffState];
    > }

    You're looking for something like:

    BOOL colorSwitch = [[temp objectForKey:@"BBLMColorsSyntax"] boolValue];
    if (colorSwitch)
      [colorBox setState:NSOnState];
    else
      [colorBox setState:NSOffState];

    The above could be simplified by eliminating the colorSwitch variable
    entirely and just putting the expression directly into the 'if'.  You
    could also use the ternary conditional operator (?:) so there would be
    only one invocation of -setState:.

    On the other hand, if you want to go belt-and-suspenders, you could
    test that the dictionary really contained the type of object you
    thought it should:

    id colorState = [temp objectForKey:@"BBLMColorsSyntax"];
    if ([colorState isKindOfClass:[NSNumber class]] && [colorState
    boolValue])
      [colorBox setState:NSOnState];
    else
      [colorBox setState:NSOffState];

    Cheers,
    Ken
  • On 22 Nov 2008, at 12:48 am, Richard S. French wrote:

    > How does one get a boolean value from a dictionary object?
    > My XML dictionary contains the value </true> under the given key.
    > Should this be retrieved as NSNumber or some other object?

    Yes, that's right.

    > I am trying to set the state of a checkbox button based on the value
    > as
    > below:
    >
    > // return syntax coloring switch
    > BOOL *colorSwitch = NO;
    > colorSwitch = [NSNumber numberWithBOOL:[temp
    > objectForKey:@"BBLMColorsSyntax"]];
    > NSLog(@"Color: %@", colorSwitch);
    > if ( colorSwitch == YES) {
    > [colorBox setState:NSOnState];
    > }
    > else {
    > [colorBox setState:NSOffState];
    > }
    >

    Unfortunately, this is just wrong.

    BOOL is a scalar type, not an object. BOOL* is a pointer to a BOOL -
    such a thing is almost never used.

    NSNumber is an object, so NSNumber* is your object reference.

    So either you want:

    BOOL colourSwitch = [[temp objectForKey:@"blah"] boolValue];

    or

    NSNumber* colourSwitch = [temp objectForKey:@"blah"];
    BOOL csBool = [colourSwitch boolValue];

    Tip:

    option-double-click stuff to reveal it in the documentation, command-
    double-click to reveal it in the headers. That will save you a ton of
    grief.

    hth,

    Graham
  • Hi,
    besides what Ken Thomases and Graham Cox already said, I have a
    remark concerning programming style:
    > if ( colorSwitch == YES) {
    > [colorBox setState:NSOnState];
    > }
    > else {
    > [colorBox setState:NSOffState];
    > }

    It is bad to test a Boolean value with "colorSwitch==NO" and it is a
    very very bad habit to test
    a Boolean value with "== YES" (there is a longer thread in this
    forum). It is not that difficult to
    smoothly deal with Boolean expressions. It's not a question of
    efficiency but a question of style,
    so the above snippet is equivalent (and more Boolean-like):

    > [colorBox setState: colorSwitch ? NSOnState : NSOffState];

    Heinrich

    --
    Heinrich Giesen
    <giesenH...>
  • On Fri, Nov 21, 2008 at 9:13 AM, Ken Thomases <ken...> wrote:
    > Next, even if you did want to construct an NSNumber from it, it's not a
    > BOOL.  So +numberWithBOOL: wouldn't be appropriate.  Any non-nil object
    > pointer would result in a true-valued NSNumber, even if [temp
    > objectForKey:@"BBLMColorsSyntax"] had given you a false-valued NSNumber.
    >

    Wandering off the track a bit, but I think this is interesting....

    It's actually not true that any non-nil object pointer will result in
    a true-valued NSNumber. BOOL is not a true boolean yes/no type, but
    rather it's just a signed char. This means that when you assign, pass,
    or return a different numerical or pointer type in a place where BOOL
    is expected the compiler will simply chop off the top bits to make it
    fit. So if the last eight bits of your pointer all happen to be 0
    (which is not that unlikely!) then your BOOL will be false instead of
    true.

    This can bite you if you try to take shortcuts with comparisons. For example:

    - (BOOL)isNotNil:(id)obj {
        return obj != nil;
    }

    Pretend for a moment that this method is not actually completely
    pointless. So you say, but any non-nil value for 'obj' is always true,
    so I can remove the comparison and just write this:

    - (BOOL)isNotNil:(id)obj {
        return obj;
    }

    Now you've set yourself up for a nasty intermittent failure. This will
    work correctly, *most* of the time. But on a significant percentage of
    non-nil 'obj' values, you'll get NO back.

    Yeah, I did this once (with a less-pointless method, of course) and it
    bit me. Fun times debugging that....

    Mike
  • Why is :

    if ( boolVar == YES) or if ( boolVar == NO)

    bad form?

    David Blanton

    David Blanton
  • On Nov 21, 2008, at 8:54 AM, David Blanton wrote:

    > Why is :
    >
    > if ( boolVar == YES) or if ( boolVar == NO)
    >
    > bad form?

    It's not bad form per se, but the former is unnecessarily redundant &
    the "== YES" can be eliminated, and the latter can be shortened using
    a !.

    Nick Zitzmann
    <http://www.chronosnet.com/>
  • On Nov 21, 2008, at 10:54 AM, David Blanton wrote:

    > Why is :
    >
    > if ( boolVar == YES) or if ( boolVar == NO)
    >
    > bad form?

    if (boolVar == YES) is bad form, but if (boolVar == NO) and if
    (boolVar != NO) is not.

    In C the concept of false has one and only one value, 0, which is
    #defined to be NO / false, etc. The concept of true, on the other
    hand, is defined as its complement. Any non-0 value. The YES check
    misses most of the not-false space.

    A lot of people will argue about the relative merits of BOOL vs bool
    vs a true boolean type and how they can only have two possible
    meanings, but that is all superceded by the fact that we are
    discussing a C type language. You don't always know where your values
    are coming from, whether they respect the types you've somewhat
    arbitrarily chosen to label them, and as such, there are no guarantees
    as to their validity. You should check the C assumptions as to their
    truthiness, not arbitrary and unenforced type assumptions.

    -Ed
  • On Nov 21, 2008, at 9:54 AM, David Blanton wrote:

    > Why is :
    >
    > if ( boolVar == YES) or if ( boolVar == NO)
    >
    > bad form?

    Let me ask you this: why wouldn't you use:

    if ( (boolVar == YES) == YES )

    or

    if ( ( (boolVar == YES) == YES ) == YES )

    ?

    boolVar is already a boolean expression.  Comparing it to YES forms
    another boolean expression, but it's redundant and more complex than
    necessary.

    In addition, although a BOOL variable arguably _should_ only contain
    YES or NO (or TRUE or FALSE), it might contain other values.  Any non-
    zero value should be interpreted as YES because that's the convention
    for booleans in C, but it may not necessarily equal YES.

    Consider:

    if ((boolVar == YES) || (boolVar == NO))
      doSomething();
    else
    {
      // We _should_ never get here, but we might!
      breakHorribly();
    }

    Regards,
    Ken
  • Another interesting thing I've seen with some compilers is when a bit flag
    is defined with a signed type:

        short someflag : 1;

    a value of it being set may be -1 rather than 1, so the only way to compare
    it according to how you want it to work is by comparing it against 0 in some
    way:

        if (!someflag) ...
        if (0 == someflag) ...
        if (false == someflag) ...
        if (0 != someflag) ...
        if (false != someflag) ...

    After all, zero is always zero, but true-ness can be anything else, unless
    you're talking probability.

    On 11/21/2008 8:51 AM, "Michael Ash" <michael.ash...> wrote:

    > On Fri, Nov 21, 2008 at 9:13 AM, Ken Thomases <ken...> wrote:
    >> Next, even if you did want to construct an NSNumber from it, it's not a
    >> BOOL.  So +numberWithBOOL: wouldn't be appropriate.  Any non-nil object
    >> pointer would result in a true-valued NSNumber, even if [temp
    >> objectForKey:@"BBLMColorsSyntax"] had given you a false-valued NSNumber.
    >>
    >
    > Wandering off the track a bit, but I think this is interesting....
    >
    > It's actually not true that any non-nil object pointer will result in
    > a true-valued NSNumber. BOOL is not a true boolean yes/no type, but
    > rather it's just a signed char. This means that when you assign, pass,
    > or return a different numerical or pointer type in a place where BOOL
    > is expected the compiler will simply chop off the top bits to make it
    > fit. So if the last eight bits of your pointer all happen to be 0
    > (which is not that unlikely!) then your BOOL will be false instead of
    > true.
    >
    > This can bite you if you try to take shortcuts with comparisons. For example:
    >
    > - (BOOL)isNotNil:(id)obj {
    > return obj != nil;
    > }
    >
    > Pretend for a moment that this method is not actually completely
    > pointless. So you say, but any non-nil value for 'obj' is always true,
    > so I can remove the comparison and just write this:
    >
    > - (BOOL)isNotNil:(id)obj {
    > return obj;
    > }
    >
    > Now you've set yourself up for a nasty intermittent failure. This will
    > work correctly, *most* of the time. But on a significant percentage of
    > non-nil 'obj' values, you'll get NO back.
    >
    > Yeah, I did this once (with a less-pointless method, of course) and it
    > bit me. Fun times debugging that....
    >
    > Mike
  • On Fri, Nov 21, 2008 at 7:54 AM, David Blanton <airedale...> wrote:
    > Why is :
    >
    > if ( boolVar == YES) or if ( boolVar == NO)
    >
    > bad form?

    (boolVar == NO) is fine.
    (boolVar == YES) is bad form (and could lead to incorrect results)

    In C, any non-zero value evaluates to true in a boolean context, so
    all of these if statements are equivalent to if(true):

    if(YES)
    if(42)
    if(3.14159)

    So it is entirely possible that you may encounter a "true" boolean
    value that isn't equal to 1:

    BOOL b = 42; //This is a true boolean, but it is not equal to YES

    if(b == YES) //This is false
    if(b) //This is true

    So, the moral of the story is *never* compare a boolean value against
    YES. At best it is redundant, and at worst it is incorrect.

    That is, never write "if(b == YES)". Instead, it's best to write
    "if(b)", "if(b != 0)" or "if(b != NO)"

    --
    Clark S. Cox III
    <clarkcox3...>
  • The issue is that a boolean value is not numeric, but the denotation
    of truth or falsehood.  If you take boolVar to represent the
    proposition that "Socrates is a man", then saying:

    if (boolVar == YES)

    is equivalent to:

    if ("Socrates is a man" == YES)

    This is obviously a correct expression - it's just that the "== YES"
    part is redundant.

    Again, when asking if a package is at the airport, you don't say, "Is
    it the case that the package is at the airport is true?", you say, "is
    the package at the airport".

    The problem is that the designers of C (and other languages as well)
    decided to treat falsehood as zero and truth as non-zero, and
    implement them using integer types.  The trick is that, implemented
    this way, boolean operators can use arithmetic ones: 'or' as addition
    and 'and' as multiplication.  For example, false or false is false (0
    + 0 = 0).

    This leads to the stripping of information: truth or falsehood gets
    reduced to numeric values and the logic of what you are coding
    changes.  I have seen examples of C code where logical values are
    compared to zero (and used in expressions with + etc operators).  From
    the above, this would be like asking:

    if ("Socrates is a man" != 0)

    which is absurd.

    To this end, I always

    #import <iso646.h>

    and use 'and' and 'or' as much as I can in my logical expressions...

    Regards,

    Karl

    On 22/11/2008, at 2:54 AM, David Blanton wrote:

    > Why is :
    >
    > if ( boolVar == YES) or if ( boolVar == NO)
    >
    > bad form?
    >
    > David Blanton
    >
    > David Blanton