Steinbitglis
Steinbitglis

Reputation: 2614

selector not sent by methodSignatureForSelector to forwardInvocation

I'm trying to change which method is called on an object for the sake of learning. Here is my code.

#import <Foundation/Foundation.h>

@interface A : NSObject
-(void) say: (NSString*) s;
-(NSMethodSignature*) methodSignatureForSelector: (SEL) aSelector;
-(void) forwardInvocation: (NSInvocation*) invocation;
@end

@implementation A
-(void) say: (NSString*) s {
  printf( "say \"%s\"", [s UTF8String] );
}
-(NSMethodSignature*) methodSignatureForSelector: (SEL) aSelector {
  return [A instanceMethodSignatureForSelector: @selector(say:)];
}
-(void) forwardInvocation: (NSInvocation*) invocation {
  // [invocation setSelector:@selector(say:)];
  [invocation invokeWithTarget:self];
}
@end

int main(int args, char* argv[]){
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  A* myObject = [[[A alloc] init] autorelease];

  [myObject tryToSay:@"Hello strange method!"];

  [pool release];
  return 0;
}

I want to use -say: no matter which method is attempted used on objects of the class A.

The result is a Segfault. It seems the invocation object sent to forwardInvocation still has @selector(tryToSay:) as its selector. Is it not supposed to get the same selector that was set in methodSignatureForSelector?

Upvotes: 3

Views: 1974

Answers (1)

Lily Ballard
Lily Ballard

Reputation: 185721

No, it's not. NSMethodSignature doesn't encode the selector. It encodes the signature of the method instead. This means things like the type and number of arguments. It's also not going to work correctly. If someone tries to invoke a method like -setInteger: which takes an NSUInteger, it will be passed to your method -say: which is expecting an NSString*. But it won't get an NSString*, it will get an NSUInteger, and any attempt to dereference that will crash (unless it's 0).

Upvotes: 3

Related Questions