[swift-evolution] Pitch: Progress Tracking in Swift

Charles Srstka cocoadev at charlessoft.com
Wed Jan 20 15:04:23 CST 2016

> On Jan 20, 2016, at 2:16 PM, Tony Parker <anthony.parker at apple.com> wrote:
> NSProgress actually has some throttling in place for cross-process progress, and I’ve found it to be very tricky to get right. As far as dropping notifications on the floor, you have to be careful that they aren’t the ones that certain clients care a lot about (e.g., getting to 100% finished). If attempting to limit it to a certain percentage, remember that any given progress object’s idea of a significant percentage may be an insignificant one for the parent progress object - and therefore too frequent. Some clients may really want every progress update and some will want it limited to something like 60Hz.

My thinking about it is that what the child process considers important doesn’t really matter, because it’s the progress object at the root of the tree that’s going to have listeners on it. When the child progress objects are updated, they will bubble their changes up the tree to the root object, and only there, where the notification handlers are registered. Any coalescing would be done in the code that calls the handlers, and thus, in the common case, in the root object.

The coalescing idea was just an idle thought, however; that’s part of the idea that I haven’t fleshed out yet. It shouldn’t be considered as essential to the idea (which is why I prefaced it with “Optional” in the description of it). If a good implementation of it could be found, though, it could be pretty useful, to clean up and streamline the worker code by removing a bunch of boilerplate that’s not directly related to the work it’s doing.

> I don’t think anything about this problem is going to be solved by simply reimplementing the entire thing in Swift. Ditching KVO may seem like a way to increase performance, but then you have to think about the global picture - how is anyone supposed to know when the progress has been updated? You will likely have to invent a different notification mechanism to replace it. At that point you’ve reinvented a chunk of KVO itself instead of focusing on the primary domain of progress reporting. Plus, the notification mechanism we’ve invented is specific to NSProgress and not general enough to plug into other systems effectively.

The Swift way to handle notifications would be simply to have the user register a closure with the progress object. I was thinking putting a few closure properties on the object, called things like progressHandler, cancellationHandler, and so on. These closures could do whatever the developer asks them to; they could update UI elements, send KVO notifications, update a property on some other object that’s bound to a UI element, etc.

KVO has its uses, to be sure; it's great for wiring things up to Interface Builder objects, for instance. However, that advantage is gone in the case of NSProgress, since the notifications don’t fire on the main thread. It’s not safe to update a view object on a secondary thread, making it unsafe to bind something like an NSProgressIndicator directly to a property on NSProgress; you have to use KVO’s awkward observation API in code to catch the notifications and forward them on to the main thread. Meanwhile, the non-trivial costs of KVO are accruing on the worker thread, slowing things down (including things like string ops to calculate properties such as localizedDescription). If things were set up such that the KVO notifications always occurred on the main thread, the value of using KVO here would be obvious, but as it’s implemented, there’s not much benefit to the KVO approach; it's just the wrong tool for the job. All IMO of course.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160120/c8c929f6/attachment.html>

More information about the swift-evolution mailing list