ProgressManager
is a class to make dealing with Progress
and its child tasks just a bit more straightforward and easy. Why use it? It allows for granular but accessible control over the details of a multistep operation, while automatically mirroring its state in views like ProgressView
, UIProgressView
, and NSProgressIndicator
.
- Create a type that you'd like to use for referencing each child task (most easily an enumeration, but could be anything that conforms to
ChildProgressTask
). It must have two properties:childUnits
andparentUnits
. See docs for more info on each.
private enum ProgressSteps: ChildProgressTask {
case importantStep, smallStep, aMultiUnitStep
var childUnits: Int64 {
switch self {
// 1 unit of this task must be completed for it to be considered "complete" by the parent
case .importantStep: 1
// 1 unit of this task must be completed for it to be considered "complete" by the parent
case .smallStep: 1
// 6 units of this task must be completed for it to be considered "complete" by the parent
case .aMultiUnitStep: 6
}
}
var parentUnits: Int64 {
switch self {
// Once all units of this child task have been completed (1 unit),
// it counts as 5 units in the context of the parent progress
case .importantStep: 5
// Once all units of this child task have been completed (1 unit),
// it counts as 1 unit in the context of the parent progress
case .smallStep: 1
// Once all units of this child task have been completed (6 units),
// it counts as 1 unit in the context of the parent progress
case .aMultiUnitStep: 1
}
}
}
- Then create an instance of
ProgressManager
using your type. When initializing yourProgressManager
, you only need to provide it with aSet
of the tasks that it cares about. If your type conforms toCaseIterable
, you can even exclude thechildTasks
parameter of the initializer.
let progress = ProgressManager(
// can be ommitted if type can be inferred
ProgressSteps.self,
// a Set of unique child tasks
childTasks: [.importantStemp, .smallStep, .aMultiUnitStep]
)
- As your code completes the tasks, you call any combination of the child task updating functions (
setCompletedUnitCount(_:forChildTask:)
,addToCompletedUnitCount(_:forChildTask:)
, andupdateCompletedUnitCount(forChildTask:updateClosure:)
).
// Perform `.importantStep`.
progress.setCompletedUnitCount(1, forChildTask: .importantStep)
// Perform `.smallStemp`.
progress.setCompletedUnitCount(1, forChildTask: .smallStemp)
// Perform `.aMultiUnitStep`.
for i in 0..<6 {
progress.addToCompletedUnitCount(i, forChildTask: .aMultiUnitStep)
}
And that's it! If you need more granular control, you can access the child tasks by either the childTasks
property or just via the subscript (progress[.aMultiUnitStep]
).