views:

252

answers:

3

For example, I print out something to the console using NSLog. Is there a way to pass all the current method's arguments to NSLog or any other function or method without looking at each of them explicitely?

For example, I have already a macro that prints useful information to the console when I just put LOGME in my code. The macro will create a call to a singleton class's logging-method and pass several useful things like _cmd and other stuff.

I would also like to catch all the arguments of that method and pass them on for printing them out automatically. Ideas, guys? Poissible?

+3  A: 

There’s no way to address all arguments in the preprocessor or Objective-C.

The only way I’m aware of is by use of the debugger. You can add a breakpoint action in Xcode to do this easily. Right click in the leftmost column of a code window, select "Built-in breakpoints" -> "Log breakpoint and arguments and auto-continue".

Nikolai Ruhe
How does the debugger do it then?
Ben S
The debugger has knowledge over the ABI (calling conventions) and uses debug symbols (created by the compiler) to map addresses in code and registers to locations and variables in source files. In short: It uses a whole bunch of tricks, that are not part of the language.
Nikolai Ruhe
+3  A: 

Use gdb. You can set a break point that logs the arguments to the method and continues.

If you insist on doing it the hard way... It's certainly not simple, but you could use the stack structure on a given architecture/ABI and make use of the Objective-C runtime to figure out how many arguments and of what size to look for. From here on out, I'm in unchartered territory; I've never done this nor would I ever bother. So YMMV...

Within your method, you can get the Method struct, then the number of arguments, then each argument type and the its size. You could then walk the stack from the address of the self parameter (i.e. &self), assuming you knew what you were doing...

Method method = class_getInstanceMethod([self class], _cmd);
unsigned nargs = method_getNumberOfArguments(method);
void *start = &self;
for(unsigned i = 0; i<nargs; i++) {
  char *argtype = method_copyArgumentType(method, i);
  //find arg size from argtype
  // walk stack given arg zie
  free(argtype);
}

Along the way you'd have to convert from the argtype string (using the Objective-C type encodings) to the size of each argument on the stack.

Of course then you'd have to derive the format string for each type, and call NSLogv with an appropriate variable argument array containing the arguments, copied from their location on the stack. Probably a lot more work than its worth. Use the debugger.

Barry Wark
Wouldn't you want the address of the `self` variable? Starting from the object pointer *in* the `self` variable is not printing the method's arguments; it's printing the object's instance variables (probably as garbage, since you'd be using the method argument types for [mis]guidance).
Peter Hosey
Barry Wark
Peter Hosey
@Peter Of course. In the future, feel free to just edit away. I trust you more than me.
Barry Wark
Great answer. But could you give me a hint how I can get the values from the stack. I would like to implement a logging routine that prints out the selector name and the argument values. It is just this final step missing ;) Thanks.
Holtwick
After doing a lot of research I ended up in this code: http://gist.github.com/653110 Maybe someone likes to contribute some more? Thanks
Holtwick
A: 

This might be what you are looking for: http://github.com/holtwick/HOLog

It was inspired by the answer of Barry Wark in this thread. BTW, we have an issue there regarding making it work on actual iOS devices. The solution we found just works for the Simulator.

Holtwick