Re: The problem with bindings
Re: The problem with bindings
- Subject: Re: The problem with bindings
- From: Gwynne <email@hidden>
- Date: Thu, 29 Jul 2004 17:48:12 -0400
On Jul 29, 2004, at 5:28 PM, Glenn Andreas wrote:
Something as simple as this doesn't work like you'd expect:
+ (void)initialize
{
[self setKeys:[NSArray arrayWithObject:@"key1"]
triggerChangeNotificationsForDependentKey:@"key2"];
[self setKeys:[NSArray arrayWithObject:@"key2"]
triggerChangeNotificationsForDependentKey:@"key3"];
}
Now [someObject setValue:anyValue forKey:@"key1"]. key2 will be
updated, but no change notification for key3. Also, you can't do
this:
Personally, I wouldn't have expected it to - after all, when key1
changes, that doesn't mean that key2 changes, just that a notification
is triggered. If there was an automatic "cascade" of notifications,
there could easily be nasty loops with unexpected behavior (say you
added that key3 triggers key1, and you change key1, does key1 also get
the notification because it passed through key2->key3->key1?).
I agree that there's a potential problem with notification looping
here, but:
1) The fact that this doesn't work is documented _nowhere_.
2) It really ought to be the coder's responsibility to not create
notification loops.
I'm quite happy with simple explicit notification changes:
[self setKeys:[NSArray arrayWithObject:@"key1",@"key2"]
triggerChangeNotificationsForDependentKey:@"key3"];
(since that's clear that key1 & key2 both trigger key3)
That's fine from a standpoint of "making it work", but conceptually
it's probably wrong. Let's give these keys real names:
key1 - dataTransferred
key2 - percentTransferred
key3 - stringRenditionOfProgress
Now our third key is constructed using the second key, which is
calculated using the first key. The third can't be constructed with
just the first one without duplicating a calculation somewhere. key3
doesn't depend on key1, it depends on key2, which just happens to
depend on key1. key3 shouldn't need to be aware key1 exists. Now if I
want to add another key that key2 depends on, I have to make sure I
change more than one [setKeys:trigger...] method call. Now we're
increasing the chance of oversights and misconceptions.
[self setKeys:[NSArray arrayWithObject:@"singleKey"]
triggerChangeNotificationsForDependentKeys:[NSArray
arrayWithObjects:...]];
Or in English, you can't easily make multiple keys dependent on a
single key; you have to call [self
setKeys:triggerChangeNotificationsForDependentKey:] with the same
array over and over.
If you find yourself with a datamodel that has this a lot, it's
trivial to add (typed in mail):
[snip]
And "Bob's your uncle" (as they say).
True, but that still involves iterating an array. I can't help thinking
that this situation comes up often enough for there to be a better way
than this.
Adopting bindings correctly requires a Major change in how you think
of and structure your model, and if you're not careful you can end up
making your code more complicated.
This is very true - it is usually _much_ easier if you use bindings
from the very start rather than try to add them to an existing
project. But at this point of having used them, I'd hate to have to
go back...(unfortunately, "let's set up a binding to do this" seems to
be my current first solution for any problem, regardless if it is
appropriate or not).
That last is exactly my problem with bindings: you quickly become used
to the pattern of thought that _anything_ can be done by binding, and
even the idea that doing it with a binding is "better" than another way
even if the other way is actually less complicated. This comes back to
where I was writing a program from scratch using bindings, and created
about a dozen NSObjectControllers so I could hook the model objects up
to each other without using my model (which was really a controller
despite the supposed use of NSController) as an intermediary for data
storage. An example is binding the "enabled" of an NSButton to the
"stringValue" of an NSTextField through an NSObjectController whose
"content" outlet points to the field using a value transformer I called
NSIsNotEmptyString. Except whoops! stringValue is just a method in
NSControl, not a KVC-compliant key. Now you have to hook the
NSTextField's delegate outlet up to your code and implement
-controlTextDidChange: to do [[notification object]
will/didChangeValueForKey:@"stringValue];
The thing to keep in mind here is that the design has deviated from the
MVC model that the NSController layer depends upon. Bindings are
designed to deal with mediating the getting, setting, and validating of
values between model and view objects. If the text field in the above
example doesn't refer to a value your model stores, such as a text
field whose value is only used when the button is clicked and never at
any other time, bindings aren't really suitable for the purpose unless
you feel like wasting an instance variable and accessor/modifier
methods to store the field value. When I ran into this, I finally said
"to heck with it", put outlets for the field and button into my object,
implemented controlTextDidChange, and called setEnabled on the button
as needed. Same effect, except this time I didn't need to create
another NSObjectController AND NSValueTransformer just to let the views
talk to each other.
-- Gwynne, key to the Code that runs us all
Email: email@hidden
Web:
http://musicimage.plasticchicken.com/
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.