【问题标题】:-forwardInvocation works with Clang - LLVM but not with GCC-forwardInvocation 适用于 Clang - LLVM 但不适用于 GCC
【发布时间】:2009-09-20 20:47:27
【问题描述】:

以下代码实现了一个 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;
} 

【问题讨论】:

    标签: objective-c gcc llvm clang


    【解决方案1】:

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

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

    由于 GCC 编译器假定返回值为 id,它使用后一个函数并错误地处理结果。 Clang 能够正确处理这个问题很有趣,但我会犹豫依赖这种行为。对于要转发的任何方法,最好在代理上声明一个类别。这还具有消除为调用floatValue 方法的代码行生成的警告的好处。

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

    【讨论】:

    • 感谢您清楚解释的答案,我认为这与期望 id 指针返回与浮动有关。只是没有看到任何有关潜在陷阱的 Apple 文档。
    【解决方案2】:

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

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

    【讨论】:

    • NSProxy 没有 init 方法。
    猜你喜欢
    • 1970-01-01
    • 2022-11-26
    • 2012-06-16
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多