Progress
Progress
is used to report the amount of work done, and provides a way to allow the user to cancel that work.
class Progress
Since work is often split up into several parts, progress objects can form a tree where children represent part of the overall total work. Each parent may have as many children as required, but each child only has one parent. The top level progress object in this tree is typically the one that you would display to a user. The leaf objects are updated as work completes, and the updates propagate up the tree.
The work that a Progress
does is tracked via a “unit count.” There are two unit count values: total and completed. In its leaf form, a Progress
is created with a total unit count and its completed unit count is updated by setting completedUnitCount
until it matches the totalUnitCount
. The progress is then considered finished.
When progress objects form nodes in trees, they are still created with a total unit count. Portions of the total are then handed out to children as a “pending unit count.” The total amount handed out to children should add up to the parent’s totalUnitCount
. When those children become finished, the pending unit count assigned to that child is added to the parent’s completedUnitCount
. Therefore, when all children are finished, the parent’s completedUnitCount
is equal to its totalUnitCount
and it becomes finished itself.
Children Progress
objects can be added implicitly or by calling addChild(withPendingUnitCount)
on the parent. Implicitly added children are attached to a parent progress between a call to becomeCurrent(withPendingUnitCount)
and a call to resignCurrent
. The implicit child is created with the Progress(totalUnitCount:)
initializer, or by passing the result of Progress.currentProgress
to the Progress(parent:userInfo:)
initializer. Both kinds of children can be attached to the same parent progress object. If you have an idea in advance that some portions of the work will take more or less time than the others, you can use different values of pending unit count for each child.
If you are designing an interface of an object that reports progress, then the recommended approach is to vend a Progress
property and adopt the ProgressReporting
protocol. The progress should be created with the Progress.discreteProgress(withTotalUnitCount:)
class function. You can then either update the progress object directly or set it up to have children of its own. Users of your object can compose your progress into their tree by using the addChild(withPendingUnitCount)
function.
If you want to provide progress reporting for a single method, then the recommended approach is to implicitly attach to a current Progress
by creating an Progress
object at the very beginning of your method using Progress(withTotalUnitCount)
. This progress object will consume the pending unit count, and then you can set up the progress object with children of its own.
The localizedDescription
and localizedAdditionalDescription
properties are meant to be observed as well as set. So are the cancellable
and pausable
properties. totalUnitCount
and completedUnitCount
, on the other hand, are often not the best properties to observe when presenting progress to the user. You should observe fractionCompleted
instead of observing totalUnitCount
and completedUnitCount
and doing your own calculation. Progress
’ default implementation of fractionCompleted
does fairly sophisticated things like taking child Progress
into account.