2011-01-06 41 views
19

我無法讓forwardInvocation正常工作。出於某種原因,Objective-C運行時完全忽略了我的forwardInvocation:方法並引發了無法識別的選擇器異常。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]時調用forwardInvocation:在SparseClass的實例上,但它被完全忽略:

- [SparseClass值]:無法識別的選擇發送到實例0x4b1c4a0 ***終止應用程序由於未捕獲的異常 'NSInvalidArgumentException',原因: ' - [SparseClass值]:無法識別的選擇發送到實例0x4b1c4a0'

回答

36

您還必須重寫- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector才能使其工作。

我猜

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

應該沒問題。

+1

太棒了!像魅力一樣工作。 – Karl 2011-01-07 01:09:46

24

NSObject文檔:

重要:要到你的對象本身不承認,你必須除了forwardInvocation:覆蓋methodSignatureForSelector:方法作出迴應。轉發消息的機制使用從methodSignatureForSelector:獲取的信息來創建要轉發的對象NSInvocation。您的覆蓋方法必須爲給定的選擇器提供適當的方法簽名,可以通過預先編寫一個或通過向另一個對象請求一個。

,並從runtime文檔:

...如果一個對象轉發接收到任何遠程的消息,它應該有一個版本的methodSignatureForSelector:,可以返回的最終響應的方法的準確的描述到轉發的消息;例如,如果一個對象是能夠將消息轉發給其代理,你將實現methodSignatureForSelector:如下:

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

注:見Jilouc的answer爲正確執行methodSignatureForSelector:

+13

我認爲Apple的運行時編程指南文檔在這個問題上失敗。在「轉發」部分,他們沒有提及需要使用`forwardInvocation:`方法`methodSignatureForSelector:`。要找到這個小技巧,你需要滾動3個部分來找出你需要實現一個節的方法。 – DBD 2012-03-08 15:45:27