Give your simulator superpowers

RocketSim: An Essential Developer Tool
as recommended by Apple

Controlling Progress children by adding remove

Controlling Progress children by default makes it only easy to add children to a Progress instance, but removing is not possible by default. This could have been useful when you want to use a single Progress instance which can have different children over time. Using a custom class MutableProgress makes this possible.

Controlling Progress children by subclassing Progress

The NSProgress instance which is renamed to Progress since Swift 3.0, is the main class to use for progress reporting in Swift. By managing the children by ourselves we’re able to control the children and add the possibility to remove children.

// Remove the Video upload progress, as the video file has been deleted by the user during upload.
totalUploadProgress.removeChild(videoUploadProgress)

By doing so, we need to make sure updates are broadcasted correctly. Therefore we need to override the properties fractionCompleted, totalUnitCount and completedUnitCount. Progress is using key value observation internally. Using willChange and didChange adds compatibility with UI elements like the UIProgressView.

/// Removes the given child from the progress reporting.
///
/// - Parameter child: The child to remove.
func removeChild(_ child: Progress) {
    willChangeValue(for: \.fractionCompleted)
    willChangeValue(for: \.completedUnitCount)
    willChangeValue(for: \.totalUnitCount)
    children.removeValue(forKey: child)?.invalidate()
    didChangeValue(for: \.totalUnitCount)
    didChangeValue(for: \.completedUnitCount)
    didChangeValue(for: \.fractionCompleted)
}

Stay updated with the best of Swift

Join over 20,003 Swift developers in SwiftLee Weekly for exclusive tips and updates. Don’t miss out – subscribe now:

You can always unsubscribe, no hard feelings.

Checking if the progress is completed

By using a simple extension it is easy to verify if a Progress instance is completed.

private extension Progress {
    var isCompleted: Bool {
        guard totalUnitCount > 0 else { return true }
        return completedUnitCount >= totalUnitCount
    }
}

Using the code in a playground

You can try it out easily using a playground and including the MutableProgress there. You can find the custom MutableProgress class here.

let totalUploadProgress = MutableProgress()
let imageUploadProgress = Progress(totalUnitCount: 1)
let videoUploadProgress = Progress(totalUnitCount: 1)

totalUploadProgress.addChild(imageUploadProgress)
totalUploadProgress.addChild(videoUploadProgress)

// Mark Image uploading as completed
imageUploadProgress.completedUnitCount = 1

print(totalUploadProgress.fractionCompleted) // 0.5
print(totalUploadProgress.isCompleted) // false

// Remove the Video upload progress, as the video file has been deleted by the user during upload.
totalUploadProgress.removeChild(videoUploadProgress)

print(totalUploadProgress.fractionCompleted) // 1.0
print(totalUploadProgress.isCompleted) // true
 
Antoine van der Lee

Written by

Antoine van der Lee

iOS Developer since 2010, former Staff iOS Engineer at WeTransfer and currently full-time Indie Developer & Founder at SwiftLee. Writing a new blog post every week related to Swift, iOS and Xcode. Regular speaker and workshop host.

Are you ready to

Turn your side projects into independence?

Learn my proven steps to transform your passion into profit.