Re: KVO notifications and threads
Re: KVO notifications and threads
- Subject: Re: KVO notifications and threads
- From: Dave Dribin <email@hidden>
- Date: Fri, 18 Jul 2008 10:04:51 -0500
On Jul 14, 2008, at 10:59 PM, Ron Lue-Sang wrote:
The argument I'm trying to make is that you, as the app implementor,
have everything you need to do what you mean and do it correctly.
Imagine this (this is kinda long winded, so buckle up):
- You have a view bound to property foo of DataObject.
- You also have WorkerObject bound to property foo of DataObject
- You have the same view bound to a property "bar" of WorkerObject
which depends on DataObject.foo
- WorkerObject is doing it's work with DataObject in a background
thread, and the view is drawing in the main thread
Okay, following...
In the scenario you're asking for, DataObject.foo changes and the
view "bounces" the KVO notification over to the main thread.
//
// for anyone reading who doesn't realize, this would really mean
doing
// [self
performSelectorOnMainThread:@selector(observeValueForKeyPath:…)… ],
and forwarding the method arguments.
//
Now WorkerObject gets the notification (again,
observeValueForKeyPath gets invoked), and it changes it's bar
property. This happens in the same thread that the change to
DataObject happened. So it could happen before the main thread gets
a chance to run and handle that performSelectorOnMainThread call
earlier (assuming no wait).
But the "bar" property KVO notification needs to be bounced to the
main thread, too, otherwise the view bound to "bar" gets notified on a
background thread, as well. Thus, if the "bar" notification gets
bounced to the main thread, it'll happen after DataObject.foo's
notification.
Note: I'm assuming that calls to performSelectorOnMainThread: with no
wait are queued up in the order they are called.
But the behaviour or contents of the bound view depends on BOTH
DataObject.foo and WorkerObject.bar. Does the order in which these
notifications arrive make a difference? Maybe. AppKit would never
know, and the ordering would be indeterminate. So this wouldn't
work. What would be a better way to do this?
Coalesce the notifications on the background thread yourself. Post
both notifications, or just one über notification, in just the order
you need. Then, this (sorta contrived) example would work with your
KVO-bouncing AppKit, right? Well, it would also work great with our
existing regular AppKit too. Because what you meant to happen isn't
obvious, so you didn't leave it up to AppKit to infer.
Does that make sense?
Sort of... I see the point you are making, but the one issue I see is:
How do you coalesce KVO notifications? As an object being observed,
you have no control over when the KVO notifications are sent. In
DataObject's case, the KVO notifications get sent automagically when
setFoo: is called. The only way to control which thread the
notifications get sent on is to call setFoo: on the desired thread.
Thus when WorkerObject calls [DataObject setFoo:], in order to
guarantee the notification happens on the main thread, it has to call
setFoo: using performSelectorOnMainThread:. Otherwise the KVO
notification will get delivered to the bound view on the background
thread.
Another possibility is to have have another @property option which
forces that property to only be updated on the main thread. Or
maybe just have the willChange/didChange happen on the main thread.
I'm not sure it would make sense to treat the main thread so
specially in Foundation/ObjC API. I think this encourages the wrong
kind of laziness.
Exactly. Plus, I typically restrict my model classes (CoreData or
otherwise) to Foundation APIs so that they could be re-used in a non-
AppKit application (say, for a command line app or daemon). Putting
main thread special cases inside model objects breaks the MVC.
Or finally, maybe NSController should take care of bouncing model
KVO notifications to the main thread.
This wouldn't help in all cases, like when you create your own non-
NSController controller. You'd be back to doing what everyone has
already suggested - take care of this in your own controller code.
The problem is that often you don't have any of your own controller
code, when bindings are used: You use one of the NSControllers to
mediate between the view and model directly.
-Dave
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden