forwardInvocation方法为什么没有被调用?

19

我在尝试使用forwardInvocation方法时遇到了问题。由于某种原因,Objective-C运行时完全忽略了我的forwardInvocation:方法,并抛出了一个未识别的选择器异常。

我的测试代码如下:

@interface InvocationTest : NSObject
{
}

+ (void) runTest;

@end


@interface FullClass: NSObject
{
    int value;
}
@property(readwrite,assign) int value;

@end

@implementation FullClass

@synthesize value;

@end


@interface SparseClass: NSObject
{
}

@end

@implementation SparseClass

- (void)forwardInvocation:(NSInvocation *)forwardedInvocation
{
    NSLog(@"ForawrdInvocation called");

    FullClass* proxy = [[[FullClass alloc] init] autorelease];
    proxy.value = 42;
    [forwardedInvocation invokeWithTarget:proxy];
}

@end


@implementation InvocationTest

+ (void) runTest
{
    SparseClass* sparse = [[[SparseClass alloc] init] autorelease];
    NSLog(@"Value = %d", [sparse value]);
}

@end

我正在使用以下资源的信息:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105 http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html

据我所知,当我调用[sparse value]时,运行时应该在SparseClass实例上调用forwardInvocation:,但它被完全忽略了:

-[SparseClass value]: unrecognized selector sent to instance 0x4b1c4a0 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SparseClass value]: unrecognized selector sent to instance 0x4b1c4a0'

2个回答

39

你还需要重写 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 方法才能使其正常工作。

我猜想

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

应该没问题。


1
太棒了!像魔法一样顺利。 - Karl

26

根据NSObject文档:

重要提示:为了响应您的对象本身无法识别的方法,您必须除了覆盖forwardInvocation:方法外,还要覆盖methodSignatureForSelector:方法。转发消息的机制使用从methodSignatureForSelector:中获得的信息创建要转发的NSInvocation对象。您的覆盖方法必须为给定选择器提供一个适当的方法签名,可以通过预先制定方法签名或请求另一个对象进行制定。

并且,根据运行时的文档:

......如果一个对象转发它接收到的任何远程消息,那么它需要拥有一个版本的methodSignatureForSelector:方法,能够返回准确描述最终响应转发消息的方法的内容。例如,如果一个对象能将消息转发给它的替代者,则应按以下方式实现methodSignatureForSelector:

- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector 
{ 
    NSMethodSignature* signature = [super methodSignatureForSelector:selector];
    if (!signature) {
       signature = [surrogate methodSignatureForSelector:selector];
    } 
    return signature;
}

注意:请参考Jilouc的答案,以获取正确实现methodSignatureForSelector:的方法。


14
我认为苹果公司的 Runtime Programming Guide 文档在这个问题上有缺陷。在“Forwarding”部分中,他们没有提及需要在 forwardInvocation: 中使用 methodSignatureForSelector: 方法。要找到这个细节,你需要向下滚动三个部分才能发现你需要实现一个小节方法。 - DBD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接