introspection objective-c

Hello,

I am investigating the possibility of building a tool that adds introspection capabilities to Objective-C classes. I want to use this tool to build a dependency injection library for objective-c. It is true that the Objective-C runtime already provides some informations, but many important aspects are missing, most notably method arguments types.

  • STEP1 - the tool will extract all required informations from source code (ex: method names, method arguments with types etc.) . This tool may be libclang based, invoked before compilation of each file
  • STEP2 - somehow it will make all extracted information available at runtime. An easy solution would be to generate for each input class the implementation of a protocol which provides missing introspection information. For example:

@protocol SomeClass(Introspection)

+(NSArray) methodArguments:(NSString*)methodName{

// generated code

}

@end

As far as I can see this can be generated in an external file and compiled in to the project.

I would like to ask your advice about this solution. My most important concerns are :

  1. This tool does the same thing as a compiler plus some extra steps. This means slower build times, because the compiler is invoked twice, once to compile and second time to extract introspection information. Is there a simple way to integrate in to clang so compilation and extraction of introspection information is done in one step ? I have played with PrintFunctionNames plugin example, but as far as I understand, the plugin cannot be executed as an extra compile step.

  2. I have already experimented with code generation in a similar context, except that in the first step I was invoking Doxygen, afterward parsing it’s xml output to generate the introspection protocol implementations for each class and finally include the generated file in to the project to compile it. It involved the coordination between several external scripts with xcode and I cannot say that it was easy to set up or fast. I wonder if there is a better/simpler way to compile generated code and include it in the final build.

I can tell you that I have more an objective-c/c background than c++ and that I am a beginner with clang.

Thank you,

Adrian Tofan

Hi Adrian,

I think you're massively underestimating the amount of introspection information already present at runtime. You can already get the types of all method arguments at run time - the runtime even provides an API for telling you the type of each argument and the number of arguments.

In the EtoileFoundation framework, we provide a complete implementation of class mirrors that uses this information for reflection.

It would help if you could suggest exactly what information you are looking for that is not present for runtime introspection already. For example, the following are all trivial to access:

- List of all classes
- All methods of a class, including names and types (return type and argument types)
- All instance variable names, offsets, and types
- All properties, including name, accessors, and so on.

About the only things that are not available for introspection are categories and C functions. With libclang, you can already get the Objective-C type encoding of C functions trivially, so I'm not sure what else you need.

David

P.S. I'm assuming that you mean @implementation when you say @protocol - otherwise your code is not Objective-C.

Have you looked at the "method_" related functions in the Objective-C runtime, for example "method_getTypeEncoding"? From the documentation:

"Returns a string describing a method's parameter and return types."

A assume this will just indicate that an argument is just an object and not what kind of object, don't know if this is enough for your needs.

Hi Adrian,

I think you're massively underestimating the amount of introspection information already present at runtime. You can already get the types of all method arguments at run time - the runtime even provides an API for telling you the type of each argument and the number of arguments.

What is really missing is argument type. As I remember there is a runtime method method_getArgumentType which is supposed to do that. The problem is that it returns the string 'id' for object arguments.

For -(id) initWithString:(NSString*) str; it will return 'id' as argument type. What I need is NSString.

I guess that this is linked to the dynamic nature of objective-c. The runtime doesn't care what kind of object is there.

In the EtoileFoundation framework, we provide a complete implementation of class mirrors that uses this information for reflection.

It would help if you could suggest exactly what information you are looking for that is not present for runtime introspection already. For example, the following are all trivial to access:

- List of all classes
- All methods of a class, including names and types (return type and argument types)
- All instance variable names, offsets, and types

it is true that for ivars the runtime keeps type information. For example runtime method ivar_getTypeEncoding returns an Objective-C type encoding.

What I did not mentioned in the original post is that I also need to support some kind of source code annotation which becomes available at runtime

About the only things that are not available for introspection are categories and C functions. With libclang, you can already get the Objective-C type encoding of C functions trivially, so I'm not sure what else you need.

As I mentioned in the original post, my solution involves a rather complicated process:

- code analysis to extract missing reflexion information
- code generation
- add generated code to project
- compile original code
- compile generated code

I wanted to see if there is no simple solution to do all that in one single step "compile original code" without modifying clang :wink: Or at least hoping that I can simplify part of the process.

P.S. I'm assuming that you mean @implementation when you say @protocol - otherwise your code is not Objective-C.

right :slight_smile: