Re: The problem with bindings
Re: The problem with bindings
- Subject: Re: The problem with bindings
- From: mmalcolm crawford <email@hidden>
- Date: Thu, 29 Jul 2004 23:05:36 -0700
On Jul 29, 2004, at 2:48 PM, Gwynne wrote:
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,
That would seem to be sufficient reason for the current behaviour --
it's clear what the path is.
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.
Why is this chance greater, and less insidious, than the coder
inadvertently creating notification loops?
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.
Have you filed an enhancement request?
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.
That, then, is user error. It's hardly the technology's "fault" (i.e.
in a derogatory sense) if it turns out to be useful! I certainly don't
turn to bindings if I simply want to connect a button to an action
method.
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];
It's not clear why you would connect the content of a controller to the
'stringValue' of a text field? This significantly diverges from the
typical expected pattern, where the content of a controller should be a
model object...
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.
And the problem is what, exactly?
mmalc
_______________________________________________
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.