[swift-evolution] Pitch: Much better-performing, Swift-native Progress replacement
rodney.brown6 at icloud.com
Wed Feb 22 15:24:10 CST 2017
I agree with your assessment that KVO may not be the right tool for this because the binding doesn't allow you to declare which thread you'd like the observation posted on. I suspect this design was supposed to be inline with the patterns of Cocoa, despite the fact that the realities of multi-thread access make its use as such somewhat more limited.
Apple themselves seemed to find a workaround by making UIProgressViews on iOS themselves responsibility for handling the KVO and threading considerations. It seems a rather ad hoc solution that shows a distinct issue with the API, and I'm curious why the update wasn't carried to NSProgressIndicator, but it works.
I think the bigger issue is: we have Progress now, and a complicated workaround for a different type of NSProgress replacement has two problems:
1. The optimisations won't carry across to Obj-C code.
2. It seems any update we make to Progress in the way you have would be somewhat hacky, and we would have a very difficult time explaining to users. This doesn't seem like a first class solution, no matter how creative it is. The value/copy semantics make the Struct Variants in the Foundation Overlay clean, but the fact this API is based on identity and encapsulation of state would make this a messy solution.
While KVO is perhaps not the best tool for this, it is the one that exists. Perhaps it's better to work on fixing NSProgress's flaws so everyone can benefit? Adding granularity controls and perhaps(?) a block/closure based callback option might fix the majority of the issues, and have the added benefit of paying dividends to everyone.
> On 23 Feb 2017, at 7:39 am, Charles Srstka <cocoadev at charlessoft.com> wrote:
>> 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...
More information about the swift-evolution