Archive for May, 2009

Invoking forward

Friday, May 22nd, 2009

Typically when you want to invoke methods on a separate thread, with a delay, back on the main thread after a long operation, etc,  you are stuck with the performSelector:onThread: methods. With performSelector you are limited to invoking with a limited number of arguments, which must be objects; it won’t auto-unbox NSValue/NSNumber/NSNull like key value coding does.

This limitation can be really frustrating, particularly when you are using NSOperation or threading in general and need your delegates to call back onto the main (UI) thread.

A possible solution is to use NSInvocation with performSelector to deal with multiple arguments and primitives, for example:

but it gets cumbersome, especially setting up the invocation instance. (BTW, the first argument is at index 2 because of the hidden arguments self and _cmd.) Also you would need to call retainArguments if your arguments were objects, that may be released by the calling thread.

Thankfully there is a better way. In a post called ‘Grab that Invocation‘ and later at Dave Dribbin’s post ‘Invoke on Main Thread‘ we can see how to get an NSInvocation instance from an NSProxy/forwardInvocation: automatically; and now we can combine the proxy with performSelector:onThread: or any of the other peformSelector methods to invoke back on the main thread, invoke on other threads, delay invocation, or other more general aspects like timing methods, debugging, logging, or security.

You can find Dave Dribbins original DDInvocationGrabber implementation in his DDFoundation library.

I’ve expanded on it a bit in GHKit, (see GHNSInvocationProxy) and plan on adding more features. If you use it with the GHNSObject+Invocation category, it gets even better:

This category also includes other performSelector helpers (supporting var args and argument lists).

What might be some other ways to use this? Maybe an NSOperationProxy that allows you to queue and prioritize invocations, or more complex debugging or analytics proxies that can keep stats of certain activities.