Question

The following code implements an NSProxy subclass which forwards methods to an NSNumber instance.

However when calling [nsproxy floatValue] I get 0.0 under GCC 4.2.

Under LLVM-Clang I get the correct answer 42.0.

Any idea what is going on?

(by the way this is running under Garbage Collection)

-(id) init;
{
    _result = [NSNumber numberWithFloat:42.0];
    return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    return [[_result class] instanceMethodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    [anInvocation setTarget:_result];
    [anInvocation invoke];
    return;
} 
Was it helpful?

Solution

Your proxy class doesn't declare the message signature for -floatValue. Since it returns a floating point number, that can be a problem. Because you haven't declared it anywhere and presumably aren't casting your proxy object to its' represented class the compiler has to guess at the method signature. In that case the GCC compiler guesses that the message will return an id pointer.

In Objective-C, depending on the signature of the message and the architecture of the machine, different functions get used for processing the message and its' return values. On x86 machines messages that return a floating point value are called through objc_msgSend_fpret while functions that return void and id use objc_msgSend.

Since the GCC compiler is assuming that the return value is an id it uses the latter function and incorrectly handles the result. That Clang is able to handle this properly is interesting but I would hesitate to rely on that behavior. It would be better to declare a category on your proxy for any methods that you'll be forwarding. That also has the benefit of removing the warning that was being generated for the line of code calling the floatValue method.

@interface Foo (ProxyMethods)
- (float)floatValue;
@end

OTHER TIPS

Any init method should call [super init]; to prevent unexpected behaviour. As so:

- (id)init {
    self = [super init];
    if (self) {
        // Your init code
    }
    return self;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top