Re: KVO & Bindings: Proxy object & change notifications
Re: KVO & Bindings: Proxy object & change notifications
- Subject: Re: KVO & Bindings: Proxy object & change notifications
- From: Ken Thomases <email@hidden>
- Date: Wed, 11 Mar 2009 00:52:01 -0500
On Mar 10, 2009, at 4:14 AM, Dave Keck wrote:
I have a preferences controller object (let's call it PrefCtrl) that's
modeled after NSUserDefaultsController (for various reasons, though,
it's a custom implementation.) As does NSUDC, it has a 'values'
property, which mediates access to the preferences. The bindings in
the UI use this 'values' proxy object to access the preferences. The
role of the proxy object is simple: it forwards KVC methods
(-valueForUndefinedKey: and setValue:forUndefinedKey:) to PrefCtrl,
which either supplies or sets the appropriate value.
[...]
The problem arises
when I have 3+ elements in the binding key path. For example, if the
button's enabled property is bound to PrefCtrl's
values.someFeature.isEnabled. In this case, when the value of
'values.someFeature.isEnabled' changes (let's assume due to another
process re-writing the preferences) is when hell breaks loose and I
get this delightful message:
Cannot remove an observer <NSKeyValueObservance 0x137d50> for the key
path "someFeature.isEnabled" from <PrefCtrl_Proxy 0x135bd0>, most
likely because the value for the key "someFeature" has changed without
an appropriate KVO notification being sent. Check the KVO-compliance
of the PrefCtrl_Proxy class.
Are you sure that PrefCtrl is returning the same proxy each time?
Also, at the time that you invoke -willChangeValueForKey: have you
already changed your internal state such that invoking [theProxy
valueForKey:@"someFeature"] returns the "after" value? It should
still return the "before" value at that point. It must not return the
"after" value until after the -willChangeValueForKey: call completes.
My question: Of course, this error is correct - the value for the
'someFeature' key DID change. But why wasn't sending
willChange/didChangeValueForKey: @"values" enough to notify the KVO
system that values.someFeature was also going to change?
It is enough. However, KVO has to unwind the set of observations on
individual objects it did along the key path. In order to do that, it
has to invoke -valueForKey: on the first object to get the second, on
the second to get the third, etc. If any of those doesn't give back
the same object it did when the original observation was established,
then it can't unwind what it did.
That's what it's complaining about. It's saying that [theProxy
valueForKey:@"someFeature"] isn't the same object it was when the
observation was established, so KVO can't unhook itself from the
object it had earlier hooked into. Note that it's attempting this
unwinding during -willChangeValueForKey:. Of course, that object
won't be the same _after_ -willChangeValueForKey: -- you are, after
all, changing it -- but it needs it to be the same _at_ -
willChangeValueForKey: for KVO's housekeeping to work.
Also, since KVO was watching the "someFeature" property of the proxy,
and that property is different than it was, but KVO never noticed that
it changed, it's reporting that the property changed in a non-KVO-
compliant fashion. Since you are using a proxy to front for your
PrefCtrl, are you also making sure that all changes of PrefCtrl's
properties cause change notifications for the proxy's virtual
properties? That is, are you forwarding all -will/didChange...
invocations on your PrefCtrl object to your proxy, at least for keys
other than "values"?
You may be able to eliminate the proxy altogether, by the way. Have
you tried having the "values" property of the PrefCtrl object just
return "self" -- the PrefCtrl object itself? That would avoid the
need to forward things in either direction, but still give you the
ability to will/didChange... the "values" property to provoke a
wholesale updating of all observers of any properties. At least, I
think that should work.
Regards,
Ken
_______________________________________________
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