-forwardInvocation与Clang-LLVM一起使用但不与GCC一起使用

时间:2009-09-20 20:47:27

标签: objective-c gcc llvm clang

以下代码实现了一个NSProxy子类,它将方法转发给NSNumber实例。

然而,当调用[nsproxy floatValue]时,我在GCC 4.2下得到0.0。

在LLVM-Clang下,我得到了正确答案42.0。

知道发生了什么事吗?

(通过这种方式在垃圾收集下运行)

-(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;
} 

2 个答案:

答案 0 :(得分:6)

您的代理类未声明-floatValue的邮件签名。由于它返回浮点数,这可能是个问题。因为你没有在任何地方声明它,并且可能没有将你的代理对象转换为它所代表的类,所以编译器必须猜测方法签名。在这种情况下,GCC编译器猜测该消息将返回id指针。

在Objective-C中,根据消息的签名和机器的体系结构,使用不同的函数来处理消息及其“返回值”。在x86机器上,返回浮点值的消息通过objc_msgSend_fpret调用,而返回voidid的函数使用objc_msgSend

由于GCC编译器假设返回值为id,因此它使用后一个函数并错误地处理结果。 Clang能够正确处理这个问题很有意思,但我会毫不犹豫地依赖这种行为。最好在您的代理上为您要转发的任何方法声明一个类别。这样做的好处是可以删除为调用floatValue方法的代码行生成的警告。

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

答案 1 :(得分:-1)

任何init方法都应调用[super init];以防止意外行为。如此:

- (id)init {
    self = [super init];
    if (self) {
        // Your init code
    }
    return self;
}