KVO & Bindings: Proxy object & change notifications
KVO & Bindings: Proxy object & change notifications
- Subject: KVO & Bindings: Proxy object & change notifications
- From: Dave Keck <email@hidden>
- Date: Mon, 9 Mar 2009 23:14:09 -1000
Hey list,
I'm having some issues with KVO and updating UI elements via bindings;
I'd greatly appreciate some clarification on the KVO-compliant way to
do what I'm attempting:
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.
Preferences can change at anytime and potentially from other
processes. (I've got the correct locking mechanisms in place, and
such.) When the preferences change from 'under the feet' of the app in
question, I expect the UI elements of the app to update accordingly
(via bindings). In order to announce that the UI elements need
updating, I wrap the preferences-updating code with
willChange/didChangeValueForKey:
- (void)preferencesOnDiskDidChangeNotification: (NSNotification *)notification
{
// This code is part of PrefCtrl
[self willChangeValueForKey: @"values"];
... read the prefs from disk, and update our in-memory prefs
dictionary to reflect the new prefs ...
[self didChangeValueForKey: @"values"];
}
Now consider when I have UI elements bound to the PrefCtrl - for
example, a button's enabled property is bound to PrefCtrl's
values.someFeature (when a value exists for the 'values.someFeature'
key path, the button's enabled, otherwise disabled.) This all works
fine - when preferences change, the enabled state of the button
reflects the current value of 'values.someFeature'. 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.
(Note that PrefCtrl_Proxy is the class name of my 'values' proxy.)
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 seems
implied that when announcing that the root segment of the key path
('values') is changing, all children keys will also be changing. But
based on this console output, I suppose not. When the preferences
change, do I really need to send willChange/didChange for every key
that's present in 'values'? (Which makes everything work, by the way,
but definitely isn't as easy as simple announcing that PrefCtrl's
'values' will change. I should also mention that I've found
keyPathsForValuesAffectingValueForKey:, but it's just as clumsy as
sending willChange/didChange for every key in 'values'.)
What's even more confusing is that everything works fine when I
exclude the 'isEnabled' suffix of the key path. That is, sending
willChange/didChangeValueForKey: @"values" is sufficient when the
button's enabled property is bound to values.someFeature; my UI
updates accordingly and I don't receive any output in the console.
I've created an example project that exhibits my problem, it's
available here: http://www.docdave.com/kvo_project.zip
I've been reading through the KVO documentation but I can't seem to
find anything relevant to this issue (I'm not sure what I would even
call this problem). Perhaps I'm blind - if you would be so kind to
point me in the right direction :)
Thanks a lot for any help!
David
_______________________________________________
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