Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

forwardInvocation not being called?

I'm having trouble getting forwardInvocation to work. For some reason, the Objective-C runtime completely ignores my forwardInvocation: method and throws an unrecognized selector exception.

My test code is as follows:

@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

I'm working off information from the following resources:

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

As far as I can tell, the runtime should be calling forwardInvocation: on the instance of SparseClass when I invoke [sparse value], but it gets completely ignored:

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

like image 214
Karl Avatar asked Jan 06 '11 23:01

Karl


2 Answers

You also have to override - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector to get it working.

I guess

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

should be ok.

like image 59
Jilouc Avatar answered Oct 13 '22 17:10

Jilouc


From the NSObject documentation:

Important: To respond to methods that your object does not itself recognize, you must override methodSignatureForSelector: in addition to forwardInvocation:. The mechanism for forwarding messages uses information obtained from methodSignatureForSelector: to create the NSInvocation object to be forwarded. Your overriding method must provide an appropriate method signature for the given selector, either by preformulating one or by asking another object for one.

And, from the runtime documentation:

... if an object forwards any remote messages it receives, it should have a version of methodSignatureForSelector: that can return accurate descriptions of the methods that ultimately respond to the forwarded messages; for example, if an object is able to forward a message to its surrogate, you would implement methodSignatureForSelector: as follows:

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

Note: See Jilouc's answer for the proper implementation of methodSignatureForSelector:.

like image 27
e.James Avatar answered Oct 13 '22 18:10

e.James