[swift-evolution] Pitch: Much better-performing, Swift-native Progress replacement

Charles Srstka cocoadev at charlessoft.com
Wed Feb 22 14:39:00 CST 2017

> On Feb 22, 2017, at 2:05 PM, Rod Brown <rodney.brown6 at icloud.com> wrote:
> I think the big argument from you, Charles, is that the progress can become arbitrarily badly performing, depending on its use, and that could have untold effects up the chain with KVO notifications firing for minor elements of work?
> I think this is a fair observation that the responsibility of a reporter shouldn’t be to rate limit the reporting rate for performance reasons. Rather, the observer should be able to adjust the reporting rate to something that is appropriate for the updates they wish to perform. A 50 pixel progress bar only theoretically needs reporting every adjustment of 1/50 of the total work, and other reporting and updating is superfluous and simply a performance problem. But why is a data task responsible for knowing that? It seems backwards.

Very much so. It has been my opinion for a long time that the back-end code is *not* the appropriate place for this stuff to be.

> Perhaps we need to examine the problem here, and how to solve that, rather than the cause? Because I agree with Tony - replacing every use of KVO on a performance basis isn’t a scalable solution.

Again, I am not advocating for replacing every use of KVO. For many cases, KVO is conceptually a great solution (even if I hate its implementation). For binding values in the UI to properties in your view controller? It’s great. For populating table views with arrays of values, or doing pretty much anything Core Data-related? It’s a godsend. However, for the specific task of progress reporting, IMO, it is Considered Harmful. We cannot reap the benefits of it, because of the threading issue.

Can we bind our UI elements to it to avoid glue code? No, because it might be updated on a background thread.

Okay, can we just be sure to wrap all updates on the main dispatch queue? No, because if we add any sub-progresses to the tree that are managed by opaque library code, we can’t know that the library will follow the same pattern. Also: without some kind of coalescing mechanism, we’ll end up with a crazy number of operations flooding the queue.

Can we fix KVO to make it fire on the main thread? No, because KVO is extensively used all over the Objective-C frameworks, and making such a large change to it is bound to break binary compatibility all over the place. Also, the need for the -willChangeValueForKey: method to complete before changing the property really hamstrings any attempts to make KVO thread-safe in a sane way.

Can we add some Swift-native KVO equivalent, and have that work the way we want it to? Yes, and this would be fantastic! But with Progress/NSProgress being the same class instead of a custom Swift class, we’d need to keep the Objective-C KVO system in place for compatibility with Objective-C code, which means we’ll still have the performance drawbacks of having -willChangeValueForKey: and -didChangeValueForKey: called every time we update it.

Can we just write our own KVO observer, observe the progress, and forward things to the main queue from there? Of course. But the UI for that is terrible compared to anything closure-based, so then why are we using KVO?

My opinion: KVO is cool for the things it’s good at, but it’s the wrong tool here.


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

More information about the swift-evolution mailing list