Progress 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.
- iOS 7.0+
- macOS 10.9+
- tvOS 7.0+
- watchOS 2.0+
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
init(parent:userInfo:) instance method or the
init(totalUnitCount:) 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
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
totalUnitCount property is incremented appropriately.
Each of the properties of a progress object, including
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.
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
becomeCurrent(withPendingUnitCount:), then create your sub-task progress objects, before finally calling
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.
If you don’t create any child progress objects between the calls to
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
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.