1

This is an intentional "fork" of the question: Obj-C introspection: How can a method reference its own selector?

I need to do the exact same thing as the OP, but whereas he didn't need to pass any arguments, I do.



I have a way already to call a method with multiple unknown arguments (NSInvocation). I have some convenience methods to do this for me, like in this question. However, having to duplicate the effort for each method in each class where this is required has led to maintenance issues, and hellish debugging when the wrong argument was passed (or in the wrong order) to the convenience method.

That itself, is a relative minor issue, but one I've been grappling for two years, and would like to solve. By having a one-line macro (like @Michael57) to call my convenience method, automatically inspecting the selector (using _cmd) and the arguments (using ?) and calling the convenience method as I wished.


Note that this is for methods with fixed argument lists and not variadic. So I'm not sure if the va_args approach will work for inspecting arguments or not.

So both from a code management perspective, and purely out of technical curiosity (if _cmd exists for selectors, there must be something for arguments?) I would like to know how standard Obj-C method arguments can be introspected.


I hope this is something very obvious I'm missing. Thanks for the help!


EDIT: Some sample code: The BASIC purpose of what I'm trying to do is to always run methods called on a certain instance, in a single thread. To do this I have a convenience method like so in an NSObject category:

- (void)performSelectorInBackground:(SEL)aSelector waitUntilDone:(BOOL)waitUntilDone withArgumentLocations:(void *)firstArg,...;

Which runs the called selector on the target object in a specific background thread mapped specifically to that instance. All this is just to avoid some sticky synchronization issues that would otherwise occur.

Maybe all this is kludgy in the first place, but I'm way past that. This code is integrated in too many places. :)

The "withArgumentLocations" variadic arguments list is a list of pointer locations that can take in both scalar values and regular Obj-C objects, thus making the usual task of calling a selector in the background with variable number and type of arguments an easy 1-line affair.


Anyway, an actual use case is as below:


- (void)loginRequestWithUsername:(NSString *)username andPassword:(NSString *)password {

if(![self isInBackgroundThread])
{
    [self performSelectorInBackground:@selector(loginRequestWithUsername:andPassword:) waitUntilDone:NO withArgumentLocations:&username, &password, nil];
    return;
}



[self isInBackgroundThread] is another convenience method which checks if the current execution thread is the "assigned" one for this instance.

So this approach has worked fine for individual method calls, but now I want to expand this to all methods within a class. This has led to issues sometimes when the "argumentLocations" are not substituted properly, or not in the right order, etc leading to hellish debugging.


Which is why I'd like to replace the above block of code with a little macro, which I can simply paste in every method to achieve what I need.


Which is why this macro should be able to query its own selector (_cmd) and the arguments (using ?) and pass these along to my performSelectorInBackground:waitUntilDone:withArgumentLocations: method.

Community
  • 1
  • 1
Dev Kanchen
  • 2,332
  • 3
  • 28
  • 40
  • 3
    Does this help? http://stackoverflow.com/questions/5788346/calling-a-selector-with-unknown-number-of-arguments-using-reflection-introspec?rq=1 – matt May 02 '13 at 17:59
  • I did come across that answer during my investigation but that doesn't help. I already have these kind of methods to do the dirty work for me. My problem is NOT repeating the argument wrapping, calls etc for each method. What I would like is to be able to create a macro so that my code maintenance cost per method is just 1-line, hence requiring the mess with argument introspection. I have the "almost-there" dispatcher code already. – Dev Kanchen May 05 '13 at 20:08
  • @matt actually I just realized my question doesn't clarify this part of my requirement completely (that I have the dirty-work methods, and I just need to figure out a way to compress them further to a single-line macro, for code-maintenance concerns). I'll edit the question a bit. Thanks for your tip. – Dev Kanchen May 05 '13 at 20:12
  • 1
    I think it would help if you gave an actual example. What's an example method call coming in, and what method call are you trying to make going out? – matt May 05 '13 at 22:52
  • Oh, I forgot to mention: you know about the low-level runtime functions, right? https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html – matt May 05 '13 at 23:20
  • I've added some sample code. Hope that clears it up a bit further. Thanks for your help and patience! – Dev Kanchen May 08 '13 at 08:47
  • 1
    Looking at this: http://www.mikeash.com/pyblog/friday-qa-2013-03-08-lets-build-nsinvocation-part-i.html ... it looks to me like you'd have to drop down to the level of assembly language. Maybe it would be better to go with `forwardInvocation:`, since it gathers up the argument values for you! – matt May 08 '13 at 14:41
  • Thanks, it looks like I'll just have to go with the proxy! – Dev Kanchen May 08 '13 at 22:30

1 Answers1

0

The first thing that comes to mind about getting an NSInvocation is you could not implement the method, and then -forwardInvocation: would be called with the properly constructed NSInvocation. But I guess that is not directly helpful since you need to implement the method and do stuff in the method. However, perhaps what you could do in -forwardInvocation: is invoke the invocation on another object ("forwarding the invocation"), where the method on that object does the real stuff. Then you could also store the invocation in some place that that method can access if necessary. Or maybe you can do the "re-run" logic you want in -forwardInvocation: itself.

newacct
  • 119,665
  • 29
  • 163
  • 224
  • Yes, NSProxy or NSObject as a proxy. It did cross my mind and is a nice, clean design. However, I wanted to investigate a way to do it with macros still, and find out if it is technically possible to investigate arbitrary arguments in any Obj-C method, especially when _cmd gives you the selector so easily. However, if no other answers come through, I'll accept this one as it's closest to my design goal of having very little duplicated code (and therefore a maintenance/debugging nightmare). – Dev Kanchen May 05 '13 at 20:14
  • Correction - "NSProxy or NSObject subclass as a proxy" – Dev Kanchen May 05 '13 at 20:24