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.

Rod

> On 23 Feb 2017, at 7:39 am, Charles Srstka <cocoa...@charlessoft.com> wrote:
> 
>> On Feb 22, 2017, at 2:05 PM, Rod Brown <rodney.bro...@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.
> 
> Charles
> 
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to