swiftprogress-barios13nsoperationqueue

'progress' property of OperationQueue not working in iOS 13


iOS 13 introduced the progress property in the OperationQueue class. At the same time Apple marked the operations and operationCount properties as deprecated which indicates they should not be used anymore for reporting progress on a queue.

My problem is that I cannot get the progress property to work as I expect it to work (which is basically out of the box). Also I could not find any documentation regarding this new property (other than that it now exists).

I tried to get it to work in a new SingleView project that has one UIProgressView on the main UIViewController. This sample is heavily inspired by https://nshipster.com/ios-13/.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var progressView: UIProgressView!

    private let operationQueue: OperationQueue = {

        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 1
        queue.underlyingQueue = .global(qos: .background)

        return queue

    }()

    override func viewDidLoad() {

        super.viewDidLoad()

        self.progressView.observedProgress = operationQueue.progress

        self.operationQueue.cancelAllOperations()
        self.operationQueue.isSuspended = true

        for i in 0...9 {

            let operation = BlockOperation {
                sleep(1)
                NSLog("Operation \(i) executed.")
            }

            self.operationQueue.addOperation(operation)

        }

    }

    override func viewDidAppear(_ animated: Bool) {

        self.operationQueue.isSuspended = false

    }

}

The console shows that the queue is running as expected (as a serial queue), but there is no movement on the progress bar.

Also KVO on the progress property directly does not work, so I suspect the progress property of the OperationQueue to be the cause of the problem rather than the UIProgressView.

Any idea what I am missing here? Or could it be a bug in iOS 13? The problem exists in the simulator as well as on an iPhone 6s Plus, both running iOS 13.3.1. Thanks!


Solution

  • I just received feedback from Apple about this. The documentation is currently well hidden in the header file NSOperation.h. Here is the extract for anybody who encounters the same problem:

    /// @property progress
    /// @discussion     The `progress` property represents a total progress of the operations executed in the queue. By default NSOperationQueue
    /// does not report progress until the `totalUnitCount` of the progress is set. When the `totalUnitCount` property of the progress is set the
    /// queue then opts into participating in progress reporting. When enabled, each operation will contribute 1 unit of completion to the
    /// overall progress of the queue for operations that are finished by the end of main (operations that override start and do not invoke super
    /// will not contribute to progress). Special attention to race conditions should be made when updating the `totalUnitCount` of the progress
    /// as well as care should be taken to avoid 'backwards progress'. For example; when a NSOperationQueue's progress is 5/10, representing 50%
    /// completed, and there are 90 more operations about to be added and the `totalUnitCount` that would then make the progress report as 5/100
    /// which represents 5%. In this example it would mean that any progress bar would jump from displaying 50% back to 5%, which might not be
    /// desirable. In the cases where the `totalUnitCount` needs to be adjusted it is suggested to do this for thread-safety in a barrier by
    /// using the `addBarrierBlock:` API. This ensures that no un-expected execution state occurs adjusting into a potentially backwards moving
    /// progress scenario.
    ///
    /// @example
    /// NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    /// queue.progress.totalUnitCount = 10;