Updating A Progress Bar (iPhone)

The UIProgressView control is a handy way to allow users to see the progress of a long – running task, but it is not immediately obvious to many new iOS developers how to update the control without blocking on the main thread. In this blog, we’ll show a simple way to accomplish this. The code can be downloaded hereProgressMeter.

Our example has a very simple interface, with a single button labeled “Go” and a progress view:


























In ViewController.h, we’ve set an outlet to the progress view and an action to the button. This property and method have been wired to the appropriate controls in interface builder.

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (nonatomic, weak) IBOutlet UIProgressView *progressBar;

- (IBAction)goPressed:(UIButton *)sender;


The next step is to define the implementation of the goPressed method. In this example, we simply count from one to ten, sleeping one second between each iteration of the loop. Of course, we could merely update the progress of the UIProgressView from inside the loop (if the loop were running on the main thread), but in a real example, the work being performed would normally be executed on another thread, to avoid blocking the UI.

Here’s our implementation:

- (IBAction)goPressed:(UIButton *)sender
    NSOperationQueue *progressQueue = [[NSOperationQueue alloc] init];
    [progressQueue addOperationWithBlock:^{
        for (int i = 1; i <= 10; i++) {
            float progressValue = (float)i/10.0;
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.progressBar setProgress:progressValue];

We’ve set up an NSOperationQueue in order to run an operation on a new thread. This particular operation is simple, so we add it directly to the queue using a block. Inside the block, we define a for-loop that runs 10 times, and sets a float value to the current loop counter divided by 10.

The progress view can only be modified on the main UI thread, which runs on the main queue. We use the dispatch_asynch function of Grand Central Dispatch to get the main queue. We then use a new block to set the progress of the progress view. The result is that the progress bar is updated once per second, moving 1/10 of the way each time.

The screen shot below was taken about eight second after the Go button was pressed.

















Note that if the Go button is pressed while the NSOperation is running on the queue, a new (identical) operation will be added to the queue. (try it and see what happens). If we want to prevent this behavior, the simplest way would be to disable the button while the queue has a running operation in it. We can inspect the operationCount property of the queue to see if any operations are running. When this value is 0, the button can be reenabled.

Leave a Comment: