본문 바로가기
모바일개발(Mobile Dev)/IOS개발(ObjectC)

background thread in iOS

by 테크한스 2015. 12. 12.
반응형


written by http://pinkstone.co.uk/how-to-execute-a-method-on-a-background-thread-in-ios/


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!


//////////////////////////////////////////// add 




Processing on the background thread

We’ll next implement the tappedProcessInBackground method.  We’ll first implement this method to just do our processing in the backend and not block the UI thread.  The code for this is actually not very complicated:

- (IBAction)tappedProcessInBackground:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//Do EXTREME PROCESSING!!!
for (int i = 0; i< 100; i++) {
[NSThread sleepForTimeInterval:.05];
NSLog(@"%i", i);
}
});

}

We first call dispatch_asycn and send in the dispatch_get_global_queue method to get theDISPATCH_QUEUE_PRIORITY_BACKGROUND.  This background queue is kind of a default very low priority queue that can be used for low priority processing. dispatch_get_global_queue is used to get shared concurrent queues, of which the background queue is one of them.  We also pass a block of code that will do the same processing we did above.  Now if you run your app and tap the Process in Background button, you’ll be able to tap the Update Label method immediately after and it will update the label.  This is because we’re doing our EXTREME processing in a background thread and not on the UI thread.

Updating the UI when our background thread is done

It’s important to know how to update the UI thread once you’re done with your expensive processing as you’ll often be pulling or opening something that will then affect the UI.  We’ll look at how to do that now.  The first thing we’re going to do is add another method to theViewController.m file:

- (void)updateLabelWhenBackgroundDone {
self.lblInfo.text = [@"Background Done!" stringByAppendingFormat:@"\n%@", self.lblInfo.text];

}

The purpose of this method is to just update the label with the text Background Done!.  We’re going to call this method when our background processing is done



The purpose of this method is to just update the label with the text Background Done!.  We’re going to call this method when our background processing is done.  Now we’ll go back and change the tappedProcessInBackground method:

- (IBAction)tappedProcessInBackground:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//Do EXTREME PROCESSING!!!
for (int i = 0; i< 100; i++) {
[NSThread sleepForTimeInterval:.05];
NSLog(@"%i", i);
}
dispatch_async(dispatch_get_main_queue(), ^{
[self updateLabelWhenBackgroundDone];
});
});
}

The only difference to this method is the call after our for loop.  The changes are another call todispatch_async.  In this call we call dispatch_get_main_queue and pass in a block which will call the updateLabelWhenBackgroundDone method.  The dispatch_get_main_queue get’s the application’s main queue which is what the UI is running on.  So we can use this to then call methods on that main queue.  Now, when we run our app, we can tap the Process in Background method, then tap the Update Label button several times, and when the background thread is done processing, our UI will be updated:



반응형