I believe that the key that you are missing is that the NSProgress class NSProgress designed to be used as a tree of progress objects. In addition, this tree is created implicitly with child objects of progress that do not need to realize that they are attached to the parent object, from where the real power comes from.
I found Foundation OS X release notes much more useful than the NSProgress class NSProgress :
https://developer.apple.com/library/Mac/releasenotes/Foundation/RN-Foundation/index.html
The reason it seems that handlers can be used for both UI controller logic and data controller logic is that when building the parent-child hierarchy, you have two sets of handlers that can be used for both. Parent handlers will be installed at the UI controller level ("consumer" of progress), and child handlers will be installed at the data controller ("provider").
Since a link can be created implicitly using becomeCurrentWithPendingUnitCount: child process object will be isolated from the parent, which will alleviate your concern that clients overwrite any data-level handlers with their own.
A call to pause or cancel a progress object will propagate this call down the tree, invoking any handlers along the way.
Example:
// UI controller level, probably a UIViewController subclass. - (void)handleDoSomethingButtonTapped:(UIButton *)sender { self.progressThatWeObserve = [NSProgress progressWithTotalUnitCount:100]; // 100 is arbitrary self.progressThatWeObserve.pausingHandler = ^{ // Update UI, reflect paused state ... }; [self.progressThatWeObserve becomeCurrentWithPendingUnitCount:100]; [self.dataController doSomethingInBackgroundWithCompletionHandler:^{ // Update UI, remove from view ... }]; [self.progressThatWeObserve resignCurrent]; } // Data controller level, a SomethingManager class maybe. - (void)doSomethingInBackgroundWithCompletionHandler:(void (^)(void)completionHandler { self.progressThatWeManipulate = [NSProgress progressWithTotalUnitCount:289234]; // eg bytes to upload self.progressThatWeManipulate.pausingHandler = ^{ // Actually suspend the network operation ... }; dispath_async(self.workerQueue, ^{ // Periodically update progress }); }
Please note that I actually did nothing, this is a theory from the documentation for reading.
source share