5

I am trying this method found in Obj-c runtime reference

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

I want to add a new method like:

- [AClass drawWithFrame:(NSRect)rect inView:(id)view]

So far I have written a C function:

void drawWithFrameInView(id this, SEL this_cmd, NSRect frame, id view){
...
} 

now I am ready to do:

BOOL success = class_addMethod(NSClassFromString(@"AClass"), 
                               @selector(drawWithFrame:inView:), 
                               (IMP)drawWithFrameInView, 
                               "v@:@:@:");

but success is never YES, I have tried the same approach with methods with simpler signatures and it worked. So I think the problem is last parameter: "v@:@:@:"

What should I pass in this case to get my new method working ?

csano
  • 13,266
  • 2
  • 28
  • 45
nacho4d
  • 43,720
  • 45
  • 157
  • 240
  • Why not name the first two arguments `self` and `_cmd`, so you can write the same code you would have written in a method? – Peter Hosey Jul 25 '11 at 11:20
  • Hummm ... just for an aesthetic reason. From the C point of view `self` and `_cmd` are supposed to be normal parameters. I didn't like the fact that a parameter was colored as keywords in Obj-C (even though they represent those keywords). That is all :) – nacho4d Jul 25 '11 at 14:37

1 Answers1

8

This will work:

char *types = [[NSString stringWithFormat:@"v@:%s@", @encode(NSRect)] UTF8String];

BOOL success = class_addMethod(NSClassFromString(@"MyClass"), 
                               @selector(drawWithFrame:inView:), 
                               (IMP)drawWithFrameInView, 
                               types);

The reason why your code doesn't work is because NSRect is not an object, it is a typedef to a struct.

Learn more about type encodings here.

Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • That seems to work (at least I got success = YES :) ). However the docs says: *Since the function must take at least two arguments—self and _cmd, the second and third characters must be “@:” (the first character is the return type)* and `types` does not contain a return type, is this because is `void` or there is some kind of inference here? – nacho4d Jul 25 '11 at 05:35
  • @nacho4d `types` ***does*** contain a return type - the first element is `'v'`, for `void`. – Jacob Relkin Jul 25 '11 at 05:38
  • 2
    I'm disappointed that `@encode(…)` isn't considered a literal. If it were, you could concatenate them at compile time: `static const char types[] = @encode(void) @encode(id) @encode(SEL) @encode(NSRect) @encode(id);` – Peter Hosey Jul 25 '11 at 11:26
  • @Peter Agreed - even better would be if `@encode` were a variadic function: `@encode(void, id, SEL, NSRect, id);` – Jacob Relkin Jul 25 '11 at 15:30
  • @Peter that sounds like a great feature request... :) – Dave DeLong Jul 25 '11 at 22:32