Objective-C method call from imp

I am trying to get a method at runtime, and then use its data structure to invoke its implementation. Just for clarification, this is for educational purposes, and not for any practical reason. So here is my code.

#import <Foundation/Foundation.h> #import <stdio.h> #import <objc/runtime.h> @interface Test : NSObject -(void)method; @end @implementation Test -(void)method { puts("this is a method"); } @end int main(int argc, char *argv[]) { struct objc_method *t = (struct objc_method*) class_getInstanceMethod([Test class], @selector(method)); Test *ztest = [Test new]; (t->method_imp)(ztest, t->method_name); [ztest release]; return 0; } 

The definition of struct objc_method as follows (defined in objc / runtime.h)

 typedef struct objc_method *Method; .... struct objc_method { SEL method_name OBJC2_UNAVAILABLE; char *method_types OBJC2_UNAVAILABLE; IMP method_imp OBJC2_UNAVAILABLE; } OBJC2_UNAVAILABLE; 

however, when I try to compile my code, I get this error.

error: dereferencing pointer to incomplete type

But when I add this to my code (explicitly declaring objc_method), it works as expected.

 struct objc_method { SEL method_name; char *method_types; IMP method_imp; }; typedef struct objc_method* Method; 

Can someone explain to me why my code works when I explicitly declare this structure, and not when I import it from objc / runtime.h? Does this have anything to do with OBJC2_UNAVAILABLE? I cannot find for this definition, but it is defined in my environment.

EDIT:

I ran gcc -E code.m -o out.m to find out what is being replaced by OBJC2_UNAVAILABLE. It turns out that OBJC2_UNAVAILABLE was defined as __attribute __ ((not available)) in my environment. Can someone explain what this means and why Method still works if this structure is "unavailable"?

+4
source share
2 answers

I just looked at the objc runtime header well and found what the problem was and how to fix it :)

So, if you look at the area of ​​the file containing the transparent definition of the structure, you will see that it is in the body:

 #if !__OBJC2__ ... #endif 

Since this is defined by IS, this means that the structure we are referring to is actually proclaimed and opaque (and therefore incomplete).

Instead, we should use the functions provided to access these members:

 IMP method_getImplementation(Method method); SEL method_getName(Method method); void method_getReturnType(Method method, char *dst, size_t dst_len); 

Etc.

You can see the full list of access methods and many other useful properties in the Runtime Reference Guide .

Hope this helps!

+6
source

Its fields were previously defined, but it is an opaque type in ObjC-2. Instead, use the runtime and do not define the fields yourself:

 int main(int argc, char *argv[]) { Method t = class_getInstanceMethod([Test class], @selector(method)); Test * ztest = [Test new]; IMP imp = method_getImplementation(t); typedef void (*fn)(id,SEL); fn f = (fn)imp; f(ztest,@selector(method)); [ztest release]; return 0; } 
+3
source

All Articles