Performing any Selector on the Main Thread

Many UI frameworks, including AppKit for Mac OS X and UIKit for iPhone OS, require that all methods to UI components are sent on the main UI thread. Cocoa and Cocoa Touch make this quite easy by providing for example -[NSObject performSelectorOnMainThread:withObject:waitUntilDone:] in Foundation. Making updating the text for a text field a snap:

[someTextField performSelectorOnMainThread:@selector(setText:)
                              	withObject:@"A new text"

But not everything is an object

Since Objective-C is a superset of C, there are still all the types from C available. Such as all the primitives, including enums, and more complex struct types. Cocoa Touch is pragmatic and will use the most proper type for the use-case, not forcing everything into a square OOP hole.

This makes it quite hard to call for example -[UIView setHidden:], that takes a single BOOL argument. Same for -[UIView setFrame:], that takes a single CGRect struct argument, that in turn consists of one CGPoint and one CGSize struct.

Every type imaginable in C can be bundled in an NSValue instance. So we could bundle up the BOOL primitive, or the CGRect struct in a NSValue object. Then pass that object to the main thread, where it is unbundled and passed to the desired method. Quite cumbersome as it requires us to bundle, and unbundle types manually, and implement at least one extra method.

There must be an easier way

It turns out that NSInvocation can also handle any imaginable C type, or else it would not be able to invoke any imaginable Objective-C method. Making a NSInvocation invoke its method on the main thread is easy enough. Just add a category to the NSInvocation class, with a new method like this:

  [self performSelectorOnMainThread:@selector(invoke)

So now all you need to do is to create a NSInvocation object, fill it in with the primitive or struct types, and invoke it on the main thread. But creating and setting up a NSInvocation object is also a bit on the boring side…

There must be an even easier way!

We could use variable argument lists from plain old C. Too bad that they are untyped?
No despair, we know the target object for our invocation, and we know what method to call. So we have what we need to fetch the NSMethodSignature object for the call, that contains all the type information we need to safely process the va_list.

Our target machine is a Mac running 32- or 64-bit Intel CPU, or an iPhone OS device with a 32 bit ARM CPU. Turns out that on both platforms va_list is simply a void* pointer, to the stack frame. Even better va_start() will always flush any argument passed into the register on the stack frame. So we can skip most of the boring argument handling, by treating the arguments like a byte buffer, only advancing and aligning the buffer according to the information in the NSMethodSignature object.

A convenience method for creating a NSInvocation object for a particular target, selector, and list of variable arguments, would turn out like this:

                     retainArguments:(BOOL)retainArguments, ...;
  va_list ap;
  va_start(ap, retainArguments);
  char* args = (char*)ap;
  NSMethodSignature* signature = [target methodSignatureForSelector:aSelector];
  NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
  if (retainArguments) {
    [invocation retainArguments];
  [invocation setTarget:target];
  [invocation setSelector:aSelector];
  for (int index = 2; index < [signature numberOfArguments]; index++) {
    const char *type = [signature getArgumentTypeAtIndex:index];
    NSUInteger size, align;
    NSGetSizeAndAlignment(type, &size, &align);
    NSUInteger mod = (NSUInteger)args % align;
    if (mod != 0) {
      args += (align - mod);
    [invocation setArgument:args atIndex:index];
    args += size;
  return invocation;


And now we can easily call any method on the main UI thread.

An example where a CGRect struct is used to update the UI components frame;

// Set new frame of a label.
[[NSInvocation invocationWithTarget:someLabel
                    retainArguments:NO, CGRectMake(40, 40, 200, 100)]

A slightly more complex example, where we send a primitive int, and also waits for and fetches the result from the main thread:

// Query a UITableView for the number of rows in section 2.
NSInvocation* i = [NSInvocation invocationWithTarget:tableView
                                     retainArguments:NO, (NSUInteger)2];
// Block this thread until method has been invoked and result is available.
[i invokeOnMainThreadWaitUntilDone:YES];
NSInteger numberOfRows;
[i getReturnValue:&numberOfRows];

Download full source code here:

Update: Example 2 was not 64-bit compatible as David Remahl pointed out to me. Added type cast to fix the error.

Update 2: A new version with some more features and small bug-fixes to BOOL, float and uint16_t types, plus proper unit tests can be downloaded here:

This Post Has 36 Comments

  1. Kalle

    I can see that this might be useful in edge cases, but I would also take it as a design warning if my background tasks ties in with my view without going through the view controller (which probably shouldn’t be threaded by itself). Most tasks I perform in background threads is stuff that really shouldn’t depend on my view. In which cases do you use this?

    1. Fredrik Olsson

      The trigger that got me started was a call to -[UIProgressView setProgress:], that takes a float, and thus needed object wrapping of the argument.

      I see and understand your point, the model should not update the view directly. As with any tool, it can be misused. But however you design your app, sooner or later the view needs to know about what the background tasks has done. And when that time comes you need to cross thread boundaries. I rather do it using an easy convenience method, than manually bundling data, manual work is alway error-prone.

  2. todd

    This is interesting. Thanks. Too bad there isn’t a cleaner way of creating the NSInvocation… the byte buffer va_arg() stuff seems a bit close to the metal as it were. What happens on a PowerPC? byte order issues taken care of? etc.

    1. Fredrik Olsson

      @todd: Not as high level as most code, but everything is according to spec; C99, Apple’s public Cocoa API, and Darwin ABI. So very safe as long as you target existing Darwin platforms.

  3. Christopher Drum

    Is there some compelling reason to jump through these hoops, rather than simply sending through an NSDictionary with all the values you could possibly hope to send? Yes, you can only send one argument, but how much more could you need to send than, “everything you can pack into a dictionary” ? Or better yet, define your own class and send an object of that type through. Then you can pack in primitive values if you so choose. I feel this is a clever engineering solution to a problem that is better solved through design.

    1. Fredrik Olsson

      @Christopher Drum: Yes, mainly because this is a category you write once and drop into your projects, in order to not jump through this hoop ever again.

      If you send the arguments in an dictionary then you have to: 1. Pack the arguments, 2. Send packed argument to placeholder method, 3. Unpack arguments, 4. Call actual method. Using this method you instead: 1. Call actual method. Each extra step you have to take, each line of code, is a potential hiding place for bugs.

      So convenience, maintainability, and safety, are the compelling reasons.

  4. todd

    Christopher – NSDictionary isn’t ordered and presumably you need to also encode the order of the parameters.

  5. Pingback: itemprop="name">iWyre

  6. Dave Murdock

    Thanks for the code.

    The for loop index should be an NSUInteger not just an int. I turned on the GCC 4.2 Sign Comparison warning and it flagged this because [signature numberOfArguments] returns an NSUInteger. Also, the variable name “index” causes the Hidden Local Variables GCC 4.2 warning to be thrown, so I renamed it to arrayIndex.

    One more thing, the code in invokeInBackground seems like it’s from your app, should the only code in that method be this?
    [self performSelectorInBackground:@selector(invoke) withObject:nil];

  7. John Haney

    How about using GCD and blocks for moving things to the main thread instead?

    dispatch_async(dispatch_get_main_queue(), ^{ [UIView setHidden:YES]; });

    Or, to wait for the execution to complete…

    dispatch_sync(dispatch_get_main_queue(), ^{ [UIView setHidden:YES]; });

    1. Fredrik Olsson

      GCD works well for most cases but have two gotchas:
      1. It does not work pre-iOS 4.0, can be a showstopper for many projects.
      2. Blocks do not handle memory, that is any block captured variable for an object instance is not retained by the block. So the simple example:
      dispatch_async(dispatch_get_main_queue(), ^{ myView.hidden = YES; });
      I no quite that simple since there is no guarantee that myView will actually still be alive when the code is executed some time later. The safe code would be:
      [myView retain]; dispatch_async(dispatch_get_main_queue(), ^{ myView.hidden = YES; [myView release]; });
      Add more captured variables and more complex use cases and it can get hairy fast. My NInvocation category abstracts this away in the single argument preceding the argument list retainArguments:YES, ....

      Both works, and I use both myself. I just find that my invocation solution handles more of the details for me in most use-cases.

  8. Xero

    I seem to have found a bug in

    NSGetSizeAndAlignment(type, &size, &align);

    which outputs an alignment always equal to size. This doesn’t work with any argument that’s < 4 bytes because the alignment is not correct. on iOS a byte or short is aligned at the 32 bit word boundary when passed to a function. However NSGetSizeAndAlignment gives an alignment of 1 or 2.
    I seem to have fixed the problem by adding
    align = min(align, size(int))
    However I'm making an assumption on how the arguments are passed which is likely to change with different architectures, its not very portable. For instance after GNUC 2 va_list is not a void* but a struct.

    Do you know of a portable way to decode the va_list?

    1. Fredrik Olsson

      Yes it is a bug in the original implementation. The ZIP-file with code that is supplied in the Update 2 footer has this bug fixed.

      The alignment can change with different architectures, and ABI:s. The ABI for Mac OS X and iOS is quite stable though, so I do not see any cause to worry.

  9. jar

    Thanks for your code.

    I modified your approach:

    [[NSInvocation invocationWithTarget:someLabel
    retainArguments:NO, CGRectMake(40, 40, 200, 100)]

    to something, that can be use like this:

    NSInvocation * inv = [NSInvocation invocationWithTarget:someLabel
    [inv setMethodParameter:&CGRectMake(40, 40, 200, 100) atIndex:0];
    [inv invokeOnMainThreadWaitUntilDone:NO];

    invocationWithTarget:selector: is just the wrapper of default initializer (creates signature with use of target and selector, calls invocationWithMethodSignature.., sets target and selector to created NSInvocation object)

    setMethodParameter: wrapps original NSInvocation setArgument (with aligned index)

    Now UIInvocation category has just few lines of code and 0 magic:). I think, this simplified solution is not bad too!

  10. bob

    This varargs stuff is very ugly. It would be much cleaner to use a proxy object that uses -forwardInvocation: to perform it on the main thread. You would call it by something like this: [[MainThreadForwardProxy proxyWithTarget:self retainArguments:YES] setFrame:CGRectMake(40, 40, 200, 100)]

    [MainThreadForwardProxy proxyWithTarget:self retainArguments:YES] returns an object that has -forwardInvocation: and -methodSignatureForSelector:. Its -methodSignatureForSelector: simply asks its target for the signature. Its -forwardInvocation doesn’t have to do any varargs monkey business because it already gets the properly set up invocation.

  11. Pingback: itemprop="name">gurnee

  12. rebornbhms

    Search business sites, newspapers, associations and assembly vocation pages

  13. abullyskack

    Please delete, i’ve posted it in wrong topic.

  14. mymoneymonitore

    Anyone who reads Old and Middle English my money monitor literary texts
    will be familiar with the mid-brown volumes of the EETS,
    with the symbol of Alfred’s jewel embossed on the front
    cover. Most of the works attributed to my money monitor King Alfred or to
    Aelfric, along with some of those by bishop Wulfstan and
    much anonymous prose and verse from the pre-Conquest period,
    are to be found within the Society’s three series my money monitor

  15. DabJeannaWags

    Hallo liebe Leute!

    Ich möchte euch gerne eine Website von mir zeigen:

    Hier findet ihr eine Sammlung der besten Filme es gibt!

    Alle paar Tage kommen neue Filme hinzu.

    Ich danke euch für euren Besuch!

  16. ButlerChrista29

    I will recommend not to wait until you earn big sum of money to buy all you need! You can get the credit loans or college loan and feel comfortable

  17. Jack

    Hey Fredrik

    We use your code successfully in one of our apps. But since the switch to 64-Bit the code seams to crash (EXC_BAD_ACCESS) . Strangely enough the crash seams only to happen in the Simulator and not on an actual device. Although I’m not 100% sure about that. Do you have any idea why? The code crashes on the following line “[invocation setArgument:args atIndex:index];”

Leave a Reply