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:

Screenshot of two expressions: <code>!  suppressUserAlerts = (bool) true </code>
      <br>
        <script async src=
and suppressUserAlerts = (BOOL) YES

" data-src="/img/9741b5d27f6c890397fa2fb263d01b3c.png" class=" lazyloaded" src="https://fooobar.com//img/9741b5d27f6c890397fa2fb263d01b3c.png">

So, confused, I ask why suppressUserAlerts

YES

and !suppressUserAlerts

true

?
And more importantly, How to get the value I want

+3


source to share


3 answers


@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.

+2


source


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.

+1


source


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.

0


source







All Articles