tags:

views:

136

answers:

2

I'm sure that this has been asked MANY times before, but it's still giving me trouble. I define my class's Boolean property like this:

@property(readwrite,assign) BOOL namesVisible;

And it doesn't give compiler errors, but it NSLogs as (null). Obviously I'm doing something wrong here, but I'm at a loss to what it is.

+2  A: 

Because you're trying to log it as an object by using %@, and a BOOL isn't an object, and your property's value is NO and you're lucky.

The last part is because you're only passing a BOOL to NSLog, but since your format string says to expect an object pointer, it will read a pointer's worth from the argument stack. Since a pointer is bigger than a BOOL, it's reading more than you passed it. You're lucky that it got zeroes for all four/eight bytes (your NO was only one of them); the result is that it sent its description message to nil, which returned nil for the description string, which prints as “(null)” in the output.

If you'd been unlucky and/or the property's value had been YES, it would have read something that isn't nil, but is nonetheless probably not a pointer to an object that exists. As such, trying to log that would cause a crash, probably of the EXC_BAD_ACCESS variety. If you'd been unlucky and lucky at the same time, you would have printed the description of an actual object, and wondered how the hell your BOOL looked like that.

The solution is one of two things:

NSLog(@"My Boolean property: %d", (int)[myObject myBooleanProperty]);

or:

NSLog(@"My Boolean property: %@", [myObject myBooleanProperty] ? @"YES" : @"NO");

The former casts the Boolean value to a full-size int and prints that value as such (most probably either 0 or 1), whereas the latter will pass either @"YES" or @"NO" as the argument depending on the Boolean value. Since NSString literals are (NSString) objects, the %@ formatter becomes the right one.

Peter Hosey
That's a great idea, and it seems to work, only I fear the problem is much deeper. I actually tried doing something with the boolean and it didn't do anything, responding as if it were indeed null, which it is. If I have a method that says do something when the boolean property is true, then the NSLog trick doesn't really help. Unless the boolean isn't actually null, and you're saying it's just returning as that?
XenElement
XenElement: As I said, a `BOOL` isn't an object. As such, you can't send messages to it. If it's `NO`, then treating it as an object pointer means you're sending a message to `nil`, with all the lack of results that implies. If it's any other value, then treating it as an object pointer would cause a crash. A `BOOL` can never truly be `NULL`, `nil`, or any other pointer value, because it is not a pointer; however, it can be `NO`, which converts to `NULL`/`nil` when converted to a pointer.
Peter Hosey
Ah. So what's the correct way to have a bool that can be set in one view and accessed in another? I assume that it's a property, but obviously I haven't done it correctly.
XenElement
XenElement: Incorrect. The property is declared and working fine. It's only your logging that's wrong.
Peter Hosey
Yes you were right, the storage keyword was screwing it up for me, and the logging. So thank you, the two answers combined helped.
XenElement
XenElement: No, the storage element was just redundant; it wasn't screwing anything up. `assign` is the default, so omitting it vs. having it makes no difference.
Peter Hosey
+3  A: 

BOOLs are just chars, either 0 or 1. As such, you don't need to use a storage keyword in the property declaration, so it should be:

@property (readwrite) BOOL namesVisible;

Second, when logging a BOOL, use the int format string, %d, or pass in a string:

NSLog(@"My Boolean: %d, or %@", object.namesVisible, object.namesVisible ? @"Yes" : @"No");
Ben Gottlieb
Okay great! That worked out, I think both of you ended up being correct, Your answer was just nicer and simpler. The problem was my NSLog and my storage keyword. So cheers, thanks for the help!
XenElement