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


