iOS Development Journal

Tips and Tricks Learned the Hard Way

Forcing Things to Run on the Main Thread

The Problem

So Apple recommends that we avoid doing too much work on the main thread. This is great advice, the less time you spend wasting CPU cycles in the main thread, the more responsive your UI will be. In my opinion a well defined iOS application will avoid doing more than update the UI on the main thread.

One prime example I’ve run into was some code that did a synchronous network request. It waited for the network response before returning and someone thought it had to run on the main thread. This resulted in a lock-up during some animations I was working on.

There’s a number of topics1 that I plan to discuss about getting things off of the main thread, but today I’m going to discuss running things on the main thread.

If you’ve set up your app to do all of the heavy lifting in some secondary thread or in a dispatch queue, you will probably need to update you UI based on this work. The first thing you’re likely to do is simply update the UIView object:

1
someUILabel.text = updatedString;

Well, it turns out that doesn’t really do anything. You might get really lucky and see the label update seconds or minutes later. The first thing to do is by adding a call to setNeedsDisplay.

1
2
someUILabel.text = updatedString;
[someUILabel setNeedsDisplay];

The next time the UI code checks to see if the UILabel has changed, it will see that, yes it has, and upate the display. Sadly, when this happens is often still fairly late.

The Solution

To really get things updated, setNeedsDisplay needs to be called from the main thread, where the UI does its work. If you can ensure that your code runs there, it should update with no noticable delay. Thankfully, Apple gave us a wonderful tool for executing small bits of code anywhere on a specific thread or queue.

1
2
3
4
dispatch_async(dispatch_get_main_queue(), ^{
    someUILabel.text = updatedString;
    [someUILabel setNeedsDisplay];
});

Suddenly your label updates the instant your code runs. The best part is it can be put in anywhere and since it runs on the main thread, the UI will update almost immediately.

So when you need to get some code to run on the main thread, usually to get your UI to update with new information, you just use dispatch_async and dispatch_get_main_queue(). Now go forth, and write responsive UIs!


  1. These include handling network calls, generally working with Grand Central Dispatch, and some common pitfalls with blocks. Look for them soon.