Why did my YES BOOL turn into a real bool from a denier?
I have the following code:
// ... [self performSelectorInBackground:@selector(mySel:) withObject:@YES]; } // ... - (void) mySel:(BOOL)suppressUserAlerts { NSError*error; [obj doActionWithError:&error]; if (!suppressUserAlerts && error) // line with breakpoint { [self alertOfError:error]; } // ...
Now, although I passed in @YES
, it is always called alertOfError:
. So naturally I debugged it and added some looked-up expressions and breakpoints and I found this nonsense:
So, confused, I ask why suppressUserAlerts
YES
and !suppressUserAlerts
true
? And more importantly, How to get the value I want
source to share
@timgcarlson is correct in his corrections.
However, to answer your question:
You are actually passing an object @YES
. IF you now have a statement
if (!supressUserAlerts) {
you are actually checking for the absence of an object (equivalently supresseUserAlerts == nil
). The declaration is BOOL
more like a cast that only affects the debugger.
So your operator will always be true because it @YES
creates an object that is not equal nil
.
EDIT
Correctly fix the error:
// ...
[self performSelectorInBackground:@selector(mySel:) withObject:@YES];
}
- (void)mySel:(NSNumber *)suppressUserAlerts {
NSError *error;
[obj doActionWithError:&error];
if (![suppressUserAlerts boolValue] && error) {
[self alertOfError:error];
}
// ...
EDIT II
I think what you see in the debugger is how it outputs a scalar boolean (generated by the prefix !
) against a bool object.
source to share
This line:
[self performSelectorInBackground:@selector(mySel:) withObject:@YES];
transfers an instance NSNumber
. You must use an object here, not a scalar value BOOL
, because it -performSelectorInBackground:withObject:
can only handle word-typed arguments (like "using Object :").
However, your method -mySel:
takes a parameter BOOL
. Nothing in the structure will automatically decompress NSNumber
to convert it to BOOL
. Instead, your method gets the value of the object pointer, but interprets it as BOOL
.
Now BOOL
it is unsigned char
or, on some architectures BOOL
. Thus, only the least significant or least significant bit is considered by the if statement. A pointer to NSNumber
will most likely be a zero byte or bit. Note that it doesn't matter what the value of the object is NSNumber
. Only its address is considered.
The debugger is probably confusing. It can do the equivalent "po <full 64-bit register value containing object pointer>". Thus, even if your program only looks at the least significant byte or bits, the debugger examines the complete 64-bit value and treats it as a pointer to an object. Thus, the debugger misleads you as to what should happen.
Like others have suggested, you can change your method -mySel:
to take NSNumber*
, not BOOL
. You will need to use a method -boolValue
to check this object value.
However, you can also avoid this kind of problem by using Grand Central Dispatch (GCD) rather than -performSelectorInBackground:withObject:
. Your code could be:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self mySel:YES];
});
There is no need to insert the value YES
into the object, so there is no problem with misinterpreting it in the method. And, if you have a type mismatch, the compiler can recognize it and warn you about it, which it cannot do with methods -performSelector...
.
Or, if you don't really need a method -mySel:
, except that you want to reference it using a selector, you can inline it directly into a block.
source to share
BOOL
is not an object in Objective-C. One way to fix this error is to pass a value BOOL
(which is 0 or 1) through NSNumber
(object).
[self performSelectorInBackground:@selector(mySel:) withObject:[NSNumber numberWithBool:YES];
- (void)mySel:(id)suppressUserAlerts {
BOOL suppressUserAlertsBool = suppressUserAlerts.boolValue;
// ...
}
EDIT: Note that you can still just pass in @YES
instead [NSNumber numberWithBool:YES]
as Cocoa will handle the transformation for you. I just used numberWithBool
to be more explicit.
source to share