Reputation: 1924
I read Mike Ash's Objective-C pitfalls page, and now I'm paranoid about implicitly casting variables of type id
to BOOL
.
Assume I have a 'dangerous' pointer with the lower bits zeroed out, so that casting it to a BOOL
would produce NO
even though it points to a valid object. Let's call this 'dangerous' pointer foo
.
How do simple if statements work?
Does the if statement cast foo
to a BOOL
when it evaluates the condition? Or does it cast to a pure boolean?
if( foo )
{
[myArray addObject:foo];
}
Does it work the same way in ternary expressions?
// Does this break when foo is 'dangerous'?
self.titleLabel.hidden = foo ? YES : NO ;
Or will the ternary only break if I do this:
// I'm pretty sure it breaks now
self.titleLabel.hidden = ((BOOL)foo) ? YES : NO ;
I feel like I'm missing something basic about logical operations in C, and how they relate to BOOL
. Please help enlighten me.
Upvotes: 3
Views: 4546
Reputation:
When does Objective-C implicitly cast to BOOL?
Never, since this phrase is semantically incorrect. A cast is, by definition, explicit. What you're asking about is called an "implicit type conversion" (coercion - thanks, Josh!).
Also, strictly speaking, the conditionals in Objective-C are not special: they're inherited from C. So expressions, when needed to evaluated as booleans, aren't treated as BOOL
, but as int
.
// Does this break when foo is 'dangerous'?`
self.titleLabel.hidden = foo ? YES : NO;
No, it doesn't. (expr)
when used as a "boolean" expression, is equivalent to (expr != 0)
. No risks here.
// I'm pretty sure it breaks now
self.titleLabel.hidden = ((BOOL)foo) ? YES : NO;
Now this can break, since BOOL
is just typedeffed to signed char
, which is 8 bit on iOS. Thus, if foo
, which is a (32-bit) pointer, gets truncated to 8 bits, and the lower 8 bits of the pointer were all zero, but the pointer itself wasn't nil
, this will incorrectly report false. You don't want to do this superfluous, ugly and dangerous cast. If you want to be more explicit, write
var = (obj != nil) ? valueOne : valueTwo;
instead.
Upvotes: 8
Reputation: 16232
There's no casting in your first two samples. Writing if(expr) is equal to writing if(expr == 0).
Your third example might indeed break in some cases, as described in the article you refer to.
Upvotes: 1