Re: bind:toObject:withKeyPath:options: Unidirectional or Bidirectional?
Re: bind:toObject:withKeyPath:options: Unidirectional or Bidirectional?
- Subject: Re: bind:toObject:withKeyPath:options: Unidirectional or Bidirectional?
- From: Quincey Morris <email@hidden>
- Date: Tue, 2 Feb 2010 12:20:52 -0800
(Apologies for over-quoting here. And for the length of the response.)
On Feb 2, 2010, at 07:42, Jerry Krinock wrote:
> On 2010 Feb 01, at 03:53, Quincey Morris wrote:
>
>> I'd point you to the the documentation:
>
> (This is the quote from "Cocoa Bindings Programming Topics" the documentation I quoted in my original post.)
>
>> I don't see how this can be clearer that bindings are bidirectional.
>
> Yes. It is clear. And I had always thought that bindings were bidirectional, based on this documentation. Then, two weeks ago, I noticed that -bind:::only implemented observer behavior in one direction.
There's no "observer behavior" *in* NSObject's 'bind:...'. It merely sets up an observation -- it does the equivalent of calling 'addObserver:forKeyPath:...'. The distinction is key. See below.
> I then read *this* documentation:
>
>> bind:toObject:withKeyPath:options:
>>
>> "Establishes a binding between a ..."
>
> "Establishes a binding!" So, then, having forgotten the other documentation, I thought like Matt, that bindings are unidirectional. Until I tried it with an NSButton.
The 'bind:...' *method* isn't a binding. It's a method. It *establishes* a binding, but it isn't a binding. Just like [NSArray array] is a method that creates an array, but the method isn't the array, nor is the array behavior in the method. See below.
> So now we have this paradox:
>
> 1. "Cocoa Bindings Programming Topics" says that bindings are bidirectional.
> 2. bind:toObject:withKeyPath:options: documentation says it "establishes a binding"
> 3. bind:toObject:withKeyPath:options: implementation establishes something which
> is unidirectional.
On Feb 2, 2010, at 10:06, Keary Suska wrote:
> No paradox, as I see it, because #3 is not precisely true. There is nothing in the docs that says it is unidirectional, except in the sense that there is always an active and passive partner (perhaps what Quincey meant by "asymmetrical").
I agree there's no paradox, but I'd express it differently. There's no paradox if a bidirectional thing contains two uni-directional pieces. Not unless you confuse the pieces with the thing.
All implementations of 'bind:...' "establish a binding [link]", which is bidirectional. NSObject's implementation of 'bind:...' "establishes something which is unidirectional" -- namely a KVO observation -- which provides half of the necessary binding behavior to subclasses that wish to make use of it. The other half (the other direction) is left for individual subclasses to implement.
Let me take another stab at teasing out the strands. Feel free to stop reading here if your eyes have already glazed over.
1. There are three (3) [III] agents involved in a binding.
-- Class A (typically some kind of view) defines+implements a binding [behavior] identified by an attribute "x". "Attribute" is not the best choice of terminology, but it's what the documentation uses. It's basically an arbitrary string with a meaning that's internal to A, though sometimes it happens to be a KVC property name too. The attribute may or may not be "exposed" to IB as a "binding name".
-- Class B (typically a data model object) defines+implements a KVC property "y".
-- Class C (typically some kind of controller) is responsible for hooking things up. If the binding is set up in IB, C's behavior is somewhere inside the nib-loading code. If the binding is established programmatically, C is an application-defined class.
2. An object c of class C establishes a binding [link] from attribute "x" of an object a of class A to property "y" of an object b of class, by sending this message:
[a bind: @"x" toObject: b withKeyPath: @"y" options: ...];
Note that A, B and C are *not* necessarily distinct. Often A == C and a == c:
[self bind: @"x" toObject: b withKeyPath: @"y" options: ...];
In terms of establishing a binding [link], that's the whole story. C does not care what the implementation of 'bind:...' is -- that's an implementation detail inside A. All C cares about is that sending this message causes the binding [link] to exist.
Certainly C knows that 'bind:...' must set up some machinery to make A's binding [behavior] work, but it's a mistake to think that this machinery *is* the binding [behavior]. That's where the discussion usually goes off the rails. The train wreck is made more likely because:
-- there's no proper terminology to distinguish a binding [link] from a binding [behavior]
-- NSObject's implementation of 'bind:...' happens to do something that's sort of useful in isolation, if class A doesn't actually define binding "x' but has a KVC property "x"
It'd be better for everyone, I think, if NSObject had no implementation of 'bind:...' at all, or if its implementation was moved to a convenience method that didn't mention the word "binding".
3. Class A is responsible for providing the binding [behavior]. This consists of three parts:
-- An implementation of NSKeyValueBindingProtocol. Most significantly, an implementation of the 'bind:...' method.
-- Detection of changes in the bound-to property ("y" in class B, above), and synchronization of its "x" attribute to such changes.
-- Propagation of changes to its "x" attribute to the bound-to property.
It can do this any way it wants. Really. An outside agent (class C) can assume *nothing* about the implementation of an arbitrary binding in A, beyond conformance to the protocol. The implementation may or may not use KVO. The implementation may or may not use NSObject's 'bind:...'.
If you follow along with the documentation, part 3 is always custom code. Part 2 is most naturally done with KVO, and set up in the 'bind:...' method. Class A might provide its own implementation of that method, or it might leverage the NSObject implementation.
4. The disputatious part of all this is whether it's valid or safe for class C to send a 'bind: @"x" ...' message to an A object when A does *not* actually provide a binding [behavior] for "x" (such as, when "x" is merely a KVC property of A).
My answer is that it's not in the API contract, so it's not a good idea. Other people seem determined to do it anyway.
_______________________________________________
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