Re: BOOL returned via -performSelctor: not BOOL on 64-bit system
Re: BOOL returned via -performSelctor: not BOOL on 64-bit system
- Subject: Re: BOOL returned via -performSelctor: not BOOL on 64-bit system
- From: Jean-Daniel Dupas <email@hidden>
- Date: Tue, 8 Jun 2010 20:20:07 +0200
Le 8 juin 2010 à 19:52, Alexander Heinz a écrit :
> On Jun 8, 2010, at 1:37 PM, Jean-Daniel Dupas wrote:
>>
>> Le 8 juin 2010 à 19:23, James Bucanek a écrit :
>>
>>> Nick Zitzmann <mailto:email@hidden> wrote (Tuesday, June 8, 2010 9:27 AM -0600):
>>>
>>>> On Jun 8, 2010, at 10:16 AM, James Bucanek wrote:
>>>>
>>>>> I've been trying to track down a peculiar bug reported by a customer, and I've narrowed it down to a problem returning a BOOL value via
>>>> -[NSObject performSelector:] on a dual Quad-Core Intel Xeon processor running 64-bit code. It seems that the returned value contains random data, which obscures the BOOL.
>>>>>
>>>>> I've included the relevant code from the project below for completeness, but the problem boils down to this statement:
>>>>>
>>>>> if ([condition performSelector:conditionSelector]!=NO)
>>>>
>>>> According to the documentation, that method returns an object, not a primitive. You can't use it if the selector returns a primitive; it doesn't work that way. If you want to call some selector and get a BOOL return value, then you must do this instead:
>>>>
>>>> BOOL returnValue = ((BOOL (*)(id, SEL))objc_msgSend)(condition, conditionSelector);
>>>
>>> For the record, the following is equivalent (i.e. produces the same machine code) and is probably a little easier to read:
>>>
>>> BOOL returnValue = (BOOL)((uintptr_t)[condition performSelector:conditionSelector]);
>>
>> It's not more valid though. -performSelector must be used only with selector that return an object.
>>
>> From the -performSelector reference:
>>
>> "For methods that return anything other than an object, use NSInvocation."
>
> Alternatively, if you can alter the method being called, (which I assume you can, since you posted the source) you could change the methods to return an NSNumber-wrapped boolean value, rather than a scalar value.
> (Standard "written-in-Mail" warning applies)
>
>> - (NSNumber*)shouldCancelAction
>> {
>> // if this condition causes actions to be skipped, apply the condition
>> return [NSNumber numberWithBool:( [self canCancelAction] ? [self test] : NO )];
>> }
>>
>> - (NSNumber*)shouldHoldAction
>> {
>> // if this condition causes actions to be held, apply the condition
>> return [NSNumber numberWithBool:( [self canHoldAction] ? [self test] : NO )];
>> }
>>
>> - (NSNumber*)shouldStopAction
>> {
>> // If this condition causes actions to abort, apply the condition
>> return [NSNumber numberWithBool:( [self canStopAction] ? [self test] : NO )];
>> }
>
> And the conditional statements change to the form:
>
>> if (![[condition performSelector:conditionSelector] boolValue])
>
> This is certainly the least performant of the recommended solutions, but if that's not a major concern, this would be my preferred way, since I think it's the easiest to read.
>
> - Alex
Don't assume without benchmarking.
NSInvocation is quite more heavyweight than boxing boolean into NSNumber objects (especially when you know that commonly used NSNumber are cached and not reallocated each time).
In fact, this code is this is a nice and efficient way to workaround the "perform selector" limitation.
-- Jean-Daniel
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden