Class

NSProgress

An object that conveys ongoing progress for a given task to the user.

Declaration

@interface NSProgress : NSObject

Overview

The NSProgress class provides a self-contained mechanism for progress reporting. It makes it easy for code that does work to report the progress of that work, and for user interface code to observe that progress for presentation to the user. Specifically, it can be used to show the user a progress bar and explanatory text, both updated properly as progress is made. It also allows work to be cancelled or paused by the user.

Reporting Progress

Using the methods of this class, your code can report the progress it’s currently making toward completing some task, including progress in related subtasks. You can create instances of this class using the initWithParent:userInfo: instance method or the progressWithTotalUnitCount: class method.

Progress objects have a number of properties that you can use to observe and report current progress. For instance, the totalUnitCount property represents the total number of units of work that need to be performed, and the completedUnitCount and fractionCompleted properties represents how much of that work has already been completed. The fractionCompleted property is useful for updating progress indicators or textual descriptors; to check whether progress is complete, you should test that completedUnitCount >= totalUnitCount (assuming, of course, that totalUnitCount > 0).

The following listing shows a sample method that reports the progress of performing some operation on a piece of data. When the progress object is first created, the value of its totalUnitCount property is set to some suitable batch size for this operation, and the completedUnitCount count is 0. Each time the loop executes and the batch of data is processed, the progress object’s completedUnitCount property is incremented appropriately.

- (void)startTaskWithData:(NSData *)data {
    NSUInteger batchSize = ... use a suitable batch size
    NSProgress *progress = [NSProgress progressWithTotalUnitCount:batchSize];
 
    for (NSUInteger index = 0; index < batchSize; index++) {
        // Check for cancellation
        if ([progress isCancelled]) {
             // Tidy up as necessary...
             break;
        }
 
        // Do something with this batch of data...
 
        // Report progress (add 1 because we've completed the work for the current index).
        [progress setCompletedUnitCount:(index + 1)];
    }
}

Each of the properties of a progress object, including totalUnitCount, completedUnitCount, and fractionCompleted, support Key-Value Observing. This makes it extremely easy for a view or window controller object to observe the properties, and update UI elements such as progress indicators when the values change. It also means that there is a non-zero cost to updating the values of these properties, so you should avoid using a unit count that is too granular—if you’re iterating over a large data set, for example, and each operation takes only a trivial amount of time, you should divide the work into batches so you can update the unit count once per batch rather than once per iteration.

Creating a Tree of Progress Objects

Often, your code may need to report the overall progress of an operation that is composed of several sub-operations. To accomplish this, your code can report the progress of each sub-operation by building up a tree of progress objects.

The NSProgress reporting mechanism supports a loosely coupled relationship between progress objects. Sub-operations don’t need to know anything about the parent progress item—you can simply create new progress objects that are added as a child of another NSProgress instance. The child object is assigned a portion of the parent’s pending unit count. When the children complete, the parent’s completedUnitCount property is automatically increased by a predefined amount.

You add child progress objects to your tree implicitly or explicitly.

Implicitly Adding a Child

Add a child implicitly by setting a pending unit count for the parent and creating a new NSProgress instance. That new instance will be set as a child of the parent and be assigned the pending unit count.

As an example, consider that you are tracking the progress of code downloading and copying files on disk. You could use a single progress object to track the entire task, but it’s easier to manage each subtask using a separate progress object. You start by creating an overall parent progress object with a suitable total unit count, then call becomeCurrentWithPendingUnitCount:, then create your sub-task progress objects, before finally calling resignCurrent.

The pending unit count that you specify in the first method is divided equally among the child progress objects you create between these two method calls. Each child progress object maintains its own internal unit count, but when it completes its units (that is, the child object’s completedUnitCount == totalUnitCount), the parent progress object’s completedUnitCount is increased by the assigned portion of the original pending unit count.

In the following example, the overall parent progress has 100 units; the two child objects therefore get 50 pending units each, and keep track internally of 10 units of work each. When each child completes its 10 units, the parent’s completed unit count is increased by 50.

- (void)startLongOperation {
    self.overallProgress = [NSProgress progressWithTotalUnitCount:100];
 
    [self.overallProgress becomeCurrentWithPendingUnitCount:50];
    [self work1];
    [self.overallProgress resignCurrent];
 
    [self.overallProgress becomeCurrentWithPendingUnitCount:50];
    [self work2];
    [self.overallProgress resignCurrent];
}
 
- (void)work1 {
    NSProgress *firstTaskProgress = [NSProgress progressWithTotalUnitCount:10];
    // Perform first task...
}
 
- (void)work2 {
    NSProgress *secondTaskProgress = [NSProgress progressWithTotalUnitCount:10];
    // Perform second task...
}

If you don’t create any child progress objects between the calls to becomeCurrentWithPendingUnitCount: and resignCurrent, the “parent” progress automatically updates its completedUnitCount by adding the pending units.

Explicitly Adding a Child

As of iOS 9.0 and OS X v10.11 you can explicitly add a child to a progress tree.

To add a child, call addChild:withPendingUnitCount: on the parent. The value for pending unit count is the amount of the parent’s totalUnitCount consumed by the child. The child usually follows the NSProgressReporting protocol.

In the following example, the overall parent progress has 10 units. The child progress for the download gets 8 units and tracks the download of a photo. The progress for the filter takes a lot less time and gets the remaining 2 units. When the download completes the parent’s completed unit count is updated by 8. When the filter completes it is updated by the remaining 2 units.

- (void)startLongOperation {
    self.overallProgress = [NSProgress progressWithTotalUnitCount:10];
 
    [self.overallProgress addChild:download.progress withPendingUnitCount:8];
    // Do the download…
 
    [self.overallProgress addChild:filter.progress withPendingUnitCount:2];
    // Perform the filter…
}

Topics

Creating Progress Objects

- initWithParent:userInfo:

Initializes a newly allocated NSProgress instance.

+ discreteProgressWithTotalUnitCount:

Creates and returns an NSProgress instance with the specified totalUnitCount that is not part of any existing progress tree. The instance is initialized using initWithParent:userInfo: with the parent set to nil.

+ progressWithTotalUnitCount:

Creates and returns an NSProgress instance, initialized using initWithParent:userInfo:.

+ progressWithTotalUnitCount:parent:pendingUnitCount:

Creates and returns an NSProgress instance attached to the specified parent with the totalUnitCount set to portionOfParentTotalUnitCount.

Current Progress Object

+ currentProgress

Returns the NSProgress instance, if any, associated with the current thread by a previous invocation of becomeCurrentWithPendingUnitCount:.

- becomeCurrentWithPendingUnitCount:

Sets the receiver as the current progress object of the current thread and specifies the portion of work to be performed by the next child progress object of the receiver.

- addChild:withPendingUnitCount:

Add a process object as a child of a progress tree. The inUnitCount indicates the expected work for the progress unit.

- resignCurrent

Balance the most recent previous invocation of becomeCurrentWithPendingUnitCount: on the same thread by restoring the current progress object to what it was before becomeCurrentWithPendingUnitCount: was invoked.

Reporting Progress

totalUnitCount

The total number of units of work tracked for the current progress.

completedUnitCount

The number of units of work for the current job that have already been completed.

localizedDescription

A localized description of progress tracked by the receiver.

localizedAdditionalDescription

A more specific localized description of progress tracked by the receiver.

Observing Progress

fractionCompleted

The fraction of the overall work completed by this progress object, including work done by any children it may have.

Controlling Progress

cancellable

Indicates whether the receiver is tracking work that can be cancelled.

cancelled

Indicates whether the receiver is tracking work that has been cancelled.

- cancel

Cancel progress tracking.

cancellationHandler

The block to invoke when progress is cancelled.

pausable

Indicates whether the receiver is tracking work that can be paused.

paused

Indicates whether the receiver is tracking work that has been paused.

- pause

Pause progress tracking.

pausingHandler

The block to invoke when progress is paused.

- resume

Resume progress tracking.

resumingHandler

The block to invoke when progress is resumed.

Progress Information

indeterminate

Indicates whether the tracked progress is indeterminate.

kind

A string identifying the kind of progress being made.

- setUserInfoObject:forKey:

Set a value in the userInfo dictionary.

userInfo

A dictionary of arbitrary values associated with the receiver.

Constants

NSProgressFileOperationKind

When tracking file operations with the progress kind set to NSProgressKindFile, you must provide a value for the NSProgressFileOperationKindKey in the user info dictionary. There are four possible values.

NSProgressUserInfoKey

Set values for these keys in the user info dictionary to affect the auto-generated localizedAdditionalDescription string.

Relationships

Inherits From

See Also

Progress

NSProgressReporting

An interface for objects that report progress using a single progress instance.

Beta Software

This documentation contains preliminary information about an API or technology in development. This information is subject to change, and software implemented according to this documentation should be tested with final operating system software.

Learn more about using Apple's beta software