Tag Archives: Grand Central Dispatch

How to execute a method on a background thread in iOS

To call something from a background thread we can use dispatch_async.

This cryptic looking statement will throw something to a background thread while the main thread can deal with other functions. This is especially useful if a method would take a long time to return and would be blocking your app while it’s waiting for an answer.

When your method comes back with a result if executes a block which can be used to react to that result.

Consider this example:

- (IBAction)mainQueue:(id)sender {
    
    // call this on the main thread
    [NSThread sleepForTimeInterval:3];
    int i = arc4random() % 100;
    self.title = [[NSString alloc]initWithFormat:@"Result: %d", i];
    
}

This method waits for 3 seconds and then presents a random number between 0 and 99. Hook it up to a button in the Single View Template. Then add a Date Picker. Don’t hook that one up though: just spin it with all your might, and then click your button to see what happens.

The Date Picker stops rolling while your action sleeps, and continues to spin when it’s finished to present the result. Simon Allardice used this trick in his course on Lynda.com – well worth watching.

Now hook up another button to the following method:

- (IBAction)backgroundQueue:(id)sender {
    
    // call the same method on a background thread
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        [NSThread sleepForTimeInterval:3];
        int i = arc4random() % 100;
        
        // update UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            self.title = [[NSString alloc]initWithFormat:@"Result: %d", i];
        });

    });
}

This looks complicated, but thanks to Xcode’s code completion it’s easy to use wherever you need. Here’s what’s happening:

We create a background queue and execute the same function as above. When it’s done we’ll grab the main queue (or main thread) again and update our UI element. This has to be done on the main thread. If you try it on the background thread it won’t work (it won’t crash either which is good to know).

Try it out! You’ll soon be dispatching all kinds of things on a background thread!

Here’s a fully working iOS 7 Demo Project on GitHub:

I’ve written another article about this subject here:





How to execute a method on another thread using Grand Central Dispatch

Everything in your iOS app happens on “the main thread” by default. It’s like at the hairdresser’s – one thing after another. Since iOS 4 however you can execute things “asynchronously” by using Grand Central Dispatch. With it comes another phenomenon called Blocks.

To make use of this feature you need to

  • define your own dispatch queue (dispatch_queue_t)
  • create your own dispatch queue (giving it a reverse DNS identifier)
  • wrap what you want to execute inside block

The syntax for this looks a bit odd and not like Objective-C, because those are “classic” C statements. As for Blocks: think of them as an anonymous function call. They allow you to specify how the background queue should react after the execution of your method has finished on the other thread.

Let’s see how this works. First define the queue, just under all those import statements will work fine:

dispatch_queue_t specialQueue;

When you’re ready to use it, give it an identifier and add an execution block:

specialQueue = dispatch_queue_create("com.versluis.specialapp", NULL);
dispatch_async(specialQueue, ^{ [self yourMethod]; });

The identifier will show up in log messages and Instruments if applicable. The block is executed at the end of the operation, on your “specialQueue”. It’s a great place to asses success or failure.

Note that UI Elements can only be updated from the main thread, so don’t change any labels from that “specialQueue”. You can however dispatch things specifically from the main queue while in your own queue:

dispatch_async(dispatch_get_main_queue(), ^{ application.networkActivityIndicatorVisible = NO; });

Here we switch off the network indicator while we’re in our own queue, by dispatching this statement on the main queue.