Re: Bindings - registering change notification for multiple keys
Re: Bindings - registering change notification for multiple keys
- Subject: Re: Bindings - registering change notification for multiple keys
- From: Ken Thomases <email@hidden>
- Date: Wed, 2 Jul 2008 06:14:57 -0500
On Jul 2, 2008, at 5:12 AM, dreamcat7 wrote:
Thank you for all of your comments Ken, very helpful.
You're welcome.
On 2 Jul 2008, at 09:16, Ken Thomases wrote:
custom class (say, "Preferences") -- again, making the dictionary
an implementation detail -- and making the keys into properties of
the Preferences class. In either case, there should be not key
path which directly accesses the NSMutableDictionary without going
through a custom setter of your own making
Yes that's good advice - it would be better to make a Preferences
object that handled all of the preferences data, and also the saving
and loading operations. Then obj-c properties for the accessor
methods. Thank you for pointing out these missing KVO/KVC
functionalities of NSMutableDictionary. I shall be sure not to use
it except for plist back-end.
See my other message. Turns out I was wrong about NSMutableDictionary
and KVO. :(
If you really need for there to be a dynamic set of properties, you
can accomplish that using valueForUndefinedKey: and
setValue:forUndefinedKey:. Basically, you have "virtual"
properties -- they won't have proper individual accessors, but the
above-named methods will be invoked whenever anything tries to
access them via KVC, and in your implementations you can simulate
their existence (by accessing the NSMutableDictionary which is part
of your implementation, for example)
If i understand correctly what you say its actually possible to
override that function for plist-type object ?
You override it in your custom class, e.g. Preferences, which is not a
plist-type object.
- setValue:(NSObject*) obj ForUndefinedKey: (NSString*) key
{
// If i have an internal representation of NSMutableDictionary for
the .plist file
[self.myMutableDict_PlistStore setValue:obj ForKey: key];
Yes, this implementation is what I would expect (modulo the case of
"forKey:"), although you might want to use NSMutableDictionary's
setObject:forKey: because its setValue:forKey: has some potentially
dangerous smarts about keys with periods in them.
// If property Key is written with a naming convention, e.g.
prefixed with letters 'PTUI'
// We may might assume it is one of our UI Element keys. And we may
include a handler for this weak type.
Didn't really follow that.
// We can to call our data store-class methods to implement the
common repetitive functionality**
// e.g. [self savePlistStore]; or we cache the PlistStore and save
it when application becomes idle.**
Yeah, you can set a dirty flag and/or queue an idle-time notification
(see NSNotificationQueue and NSPostWhenIdle).
}
So to confirm it will be triggered whenever any other object tries
to access or save an undeclared property ?
Its also likely that elsewhere in the code accessing these non-
existent properties give rise to some compiler warnings (!! ).
The undefined-key methods are only triggered when something uses KVC
to set a property. If you're getting compiler warnings, then you're
not using KVC, and you'll get errors.
That's an important consideration with this approach. Since you're
going totally dynamic with KVC, you lose a variety of compiler
checking on what you're doing. A typo in a key or key path string
could result in a hard-to-notice bug.
If you have code somewhere which is currently using real accessors,
and which after a switch to this scheme would be hard-coding key
names, then that suggests you have some "real" properties which are
known in advance. In that case, I recommend creating normal
properties rather than relying on this undefined key mechanism. A
_lot_ of the tedium of implementing such properties is eliminated by
Objective-C 2.0's @property feature.
However for a more complex UI and many IB controls / outlets it
means fewer (1) places to repeat that complexity on the model-side.
Certain larger cocoa apps - could benefit by using this approach.
Again, my suggestion was for cases where you truly need run-time
dynamism in the set of properties supported by an object. Plenty of
large Cocoa apps work just fine without going to this extreme. There
are plenty of mechanisms for eliminating this complexity.
From what you've said about maintainability, you seem to think that
having real properties will present a maintainability problem. I
suspect you've got that backwards. I suspect that going with full
dynamism when you don't have to will result in a maintainability
problem.
** and in real-world application i no longer need to wire all
controls to target action "uiSateState". Then binding to the
undefined key 'PTUI(ElementName)' is neater.
Again, didn't follow that. It seems you're carrying on a side
conversation with someone else, maybe?
It is weak-typing, but allows dynamic UI elements. And more coherent
- looking code. This [self savePlistStore] is equivalent to
synthetic property anyPreferences ( which Ken describe also for
dependantKeys method below).
Well, not quite equivalent. I think what you're saying is that using
the setValue:forUndefinedKey: gives you an opportunity to save your
model, and therefore you don't need to have an observer watching for
changes to properties of the model, if that observer were only doing
so in order to save the model. So, while I disagree that
savePlistStore is "equivalent" to anyPreferences, I can see how
setValue:forUndefinedKey: would obviate the need for observing
anyPreferences.
In the case of a static set of properties, the best thing to do is
implement +keyPathsForValuesAffectingAnyPreferences in the
Preferences class and return a set of the names of all of those
properties:
+keyPathsForValuesAffectingAnyPreferences
{
return [NSSet setWithObjects:@"debug", /* list the other
preference names here... */, nil];
If i declared my properties in the Preferences class, maybe there's
a way to dump those list in obj-c from the class object and use it
here.
I was suggesting that +keyPathsForValuesAffectingAnyPreferences be
implemented on the Preferences class, in the case where you have a
static set of properties. It doesn't seem reasonable to me that the
Preferences class would want to consult the Objective-C runtime to
learn its own properties. It should already know them! That's part
of the responsibilities of a class.
Again, it seems to me that you're taking dynamism to an unreasonable
extreme.
If not then it might be a workaround to subclass the NSObject class
to find the list of properties that belong to it.
If you use the Objective-C 2.0 "declared property" (@property)
feature, it does provide property introspection if you insist on going
that route. Remember, though, that you don't want the
"anyPreferences" property to depend on _every_ property of the class,
because that would make it dependent on itself. Even beyond the issue
of making a property depend on itself, I suspect you'll find that the
Preferences class has several properties which should not affect
"anyPreferences" -- for example, if the Preferences class maintains a
reference to its store by file path. So, I think you will always want
to state explicitly in code the list of key paths on which
"anyPreferences" depends. Doing otherwise opens you up to unintended
consequences in the future.
Also remember that, if you implement "virtual" properties using the
undefined-key methods, then there's no such thing as "the list of
properties for this class". With that much dynamism, then each
_instance_ has its own set of properties which can change at will.
Cheers,
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