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'
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.
From the NSObject documentation:
Important: To respond to methods that your object does not itself recognize, you must override
methodSignatureForSelector:
in addition toforwardInvocation:
. The mechanism for forwarding messages uses information obtained frommethodSignatureForSelector:
to create theNSInvocation
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 implementmethodSignatureForSelector:
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:
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With