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 topics[1] 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:

{% highlight objc %}
someUILabel.text = updatedString;
{% endhighlight %}

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.

{% highlight objc %}
someUILabel.text = updatedString;
[someUILabel setNeedsDisplay];
{% endhighlight %}

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.

{% highlight objc %}
dispatch_async(dispatch_get_main_queue(), ^{
someUILabel.text = updatedString;
[someUILabel setNeedsDisplay];
{% endhighlight %}

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. ↩︎