You should be able to do this:
Method method = class_getInstanceMethod([ParentParentClass class], @selector(myMethod));
IMP imp = method_getImplementation(method);
((void (*)(id, SEL))imp)(self, @selector(myMethod)); // cast the function to the correct signature
You may need to #import <objc/runtime.h>
in order for this to compile.
This gets the actual C function that the method is translated to at compile time, which you can then call. When the Objective-C compiler compiles your code, all methods are translated into plain C functions, which take self
as their first argument, and _cmd
, the selector for the current method as the second argument, followed by all of the other arguments that the Objective-C method takes. class_getInstanceMethod
obtains the runtime representation of the given method (including various metadata), and method_getImplementation
gets the plain C function pointer from that method.
If you look at the Objective-C runtime header, you'll see that the IMP
type is defined as typedef id (*IMP)(void);
, so you need to cast it to the actual type of the method implementation function, which will be (return_type (*)(id, SEL, method_arguments_in_order))
— the function takes self
and the method selector as its first two arguments, followed by the ObjC method parameters.
So, once you have the standard C function pointer, you can simply call it as you would call a function.
I wouldn't go so far as to call this approach hacky, but it certainly is non-standard, as made clear by the need to use the underlying runtime methods directly to achieve what you want. I would definitely consider this a better solution, in terms of design, reliability and making sense, than adding bridging methods in the superclass that call its superclass' methods.