Why aren't my bindings firing?
-
Okay, in a project I'm working on, I made the mistake of trying to do
something simple with the weird deep magic known as Cocoa Bindings.
I've got two classes - let's call them "Foo" and "Bar". Foo's
implementation has this in it:
- (void)setDisplayName:(NSString *)name {
[self willChangeValueForKey:@"displayName"];
NSLog(@"setting display name to %@", name);
if(name != ivar_displayName) {
[ivar_displayName release];
ivar_displayName = [name copy];
}
[self didChangeValueForKey:@"displayName"];
}
whereas Bar's implementation has this:
- (void)setTitle:(NSString *)title {
[self willChangeValueForKey:@"title"];
NSLog(@"setting title to %@", title);
if(title != ivar_title) {
[ivar_title release];
ivar_title = [title copy];
}
[self didChangeValueForKey:@"title"];
}
Foo and Bar are both instantiated in Interface Builder, and Foo has an
outlet to Bar. There's also an NSObjectController that's got its
content outlet pointed at Foo. Foo has an outlet called
"ivar_controller" that points to that NSObjectController. Foo's also
got a method that returns its Bar outlet:
- (Bar *)bar {
return ivar_bar;
}
and in Foo's windowControllerDidLoadNib: method (it's an NSDocument
subclass) I've got this:
[[self bar] bind:@"title" toObject:ivar_controller
withKeyPath:@"selection.displayName" options:nil];
Now here's the thing: if I call setDisplayName: on Foo, it calls Bar's
setTitle: method, exactly as it should. However, if I call setTitle:
on Bar, it does *not* end up calling Foo's setDisplayName: method,
although it seems like it should. I can change the
bind:toObject:withKeyPath:options: invocation above so that it binds
Bar directly to Foo without going through the object controller, or I
can try going the other way and binding the Foo to the Bar - always I
get the same result.
I'm sure I'm doing something stupid and/or missing something really
simple, but what?
Thanks,
Charles -
6/27/08 1:37 PM, also sprach <cocoadev...>:
> I've got two classes - let's call them "Foo" and "Bar". Foo's
> implementation has this in it:
>
> - (void)setDisplayName:(NSString *)name {
> [self willChangeValueForKey:@"displayName"];
>
> NSLog(@"setting display name to %@", name);
>
> if(name != ivar_displayName) {
> [ivar_displayName release];
> ivar_displayName = [name copy];
> }
>
> [self didChangeValueForKey:@"displayName"];
> }
>
> whereas Bar's implementation has this:
>
> - (void)setTitle:(NSString *)title {
> [self willChangeValueForKey:@"title"];
>
> NSLog(@"setting title to %@", title);
>
> if(title != ivar_title) {
> [ivar_title release];
> ivar_title = [title copy];
> }
>
> [self didChangeValueForKey:@"title"];
> }
If you aren't overriding +automaticallyNotifiesObserversForKey: to return
NO, you should not be calling willChangeValueForKey/didChangeValueForKey in
your setters. They are KVC-compliant as shown. Fix that, then see if the
problem goes away.
Best,
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business" -
On Jun 27, 2008, at 5:17 PM, Keary Suska wrote:
> If you aren't overriding +automaticallyNotifiesObserversForKey: to
> return
> NO, you should not be calling willChangeValueForKey/
> didChangeValueForKey in
> your setters. They are KVC-compliant as shown. Fix that, then see if
> the
> problem goes away.
Actually, that's what I tried first - I added the willChange/didChange
methods to see if that would fix the problem. It didn't - it behaves
the same way with or without those methods. I've also tried overriding
+automaticallyNotifiesObserversForKey: to return NO, but it turns out
that that method never even ends up getting called (I put a log in it
to check).
Thanks,
Charles -
On Jun 27, 2008, at 2:37 PM, Charles Srstka wrote:
> and in Foo's windowControllerDidLoadNib: method (it's an NSDocument
> subclass) I've got this:
>
> [[self bar] bind:@"title" toObject:ivar_controller
> withKeyPath:@"selection.displayName" options:nil];
>
> Now here's the thing: if I call setDisplayName: on Foo, it calls
> Bar's setTitle: method, exactly as it should. However, if I call
> setTitle: on Bar, it does *not* end up calling Foo's
> setDisplayName: method, although it seems like it should. I can
> change the bind:toObject:withKeyPath:options: invocation above so
> that it binds Bar directly to Foo without going through the object
> controller, or I can try going the other way and binding the Foo to
> the Bar - always I get the same result.
>
> I'm sure I'm doing something stupid and/or missing something really
> simple, but what?
A binding is not just an automated two-way connection between KVC/KVO-
conforming properties.
In particular, the binding name you pass to
bind:toObject:withKeyPath:options: is not in the same "namespace" as
properties. Binding names are something else. Furthermore,
implementing bindings is more than just creating KVC/KVO-conforming
properties. A binding is a specific feature of a class which
requires a specific implementation. See "How Do Bindings Work?" in
the Cocoa Bindings Programming Topics to see code listings which
illustrate the work that must be done to make a class support a binding.
http://developer.apple.com/documentation/Cocoa/Conceptual/
CocoaBindings/Concepts/HowDoBindingsWork.html
You might be tempted to create a two-way connection between
properties by using KVO. It might work, but I suspect you'll get
infinite loops.
As a matter of design, you shouldn't hook two properties up in this
way to try to keep them always equal. If they're always equal, why
store the data in two places? The state of the application (or
document or whatever) should be stored (once) in the model. The
controller is responsible for reading the state of the model and
configuring the view to reflect that. (Both parts of that may be
automated using KVO, but note that both the controller and the view
will have to implement specific response to the KVO notifications.
The view's specific response is part of implementing a binding.) In
response to user manipulation, a view may inform the controller of
some action or new value. (Again, this part of the view's behavior
may be implemented for a binding, in which case it might inform the
controller using KVC.) The controller in turn translates that action
or value change into instructions to the model to modify itself.
(This is often custom, direct invocation of the model's methods, but
may also be done via KVC.)
I responded to a similar question the other day, and that thread may
also be helpful: <http://lists.apple.com/archives/cocoa-dev/2008/Jun/
msg01484.html>.
Cheers,
Ken -
On Jun 27, 2008, at 8:06 PM, Ken Thomases wrote:
> A binding is not just an automated two-way connection between KVC/
> KVO-conforming properties.
>
> In particular, the binding name you pass to
> bind:toObject:withKeyPath:options: is not in the same "namespace" as
> properties. Binding names are something else. Furthermore,
> implementing bindings is more than just creating KVC/KVO-conforming
> properties. A binding is a specific feature of a class which
> requires a specific implementation. See "How Do Bindings Work?" in
> the Cocoa Bindings Programming Topics to see code listings which
> illustrate the work that must be done to make a class support a
> binding.
>
> http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Con
cepts/HowDoBindingsWork.html
>
>
> You might be tempted to create a two-way connection between
> properties by using KVO. It might work, but I suspect you'll get
> infinite loops.
>
> As a matter of design, you shouldn't hook two properties up in this
> way to try to keep them always equal. If they're always equal, why
> store the data in two places? The state of the application (or
> document or whatever) should be stored (once) in the model. The
> controller is responsible for reading the state of the model and
> configuring the view to reflect that. (Both parts of that may be
> automated using KVO, but note that both the controller and the view
> will have to implement specific response to the KVO notifications.
> The view's specific response is part of implementing a binding.) In
> response to user manipulation, a view may inform the controller of
> some action or new value. (Again, this part of the view's behavior
> may be implemented for a binding, in which case it might inform the
> controller using KVC.) The controller in turn translates that
> action or value change into instructions to the model to modify
> itself. (This is often custom, direct invocation of the model's
> methods, but may also be done via KVC.)
Well I'll admit that I'm relatively new to bindings, because most of
the work I've done with Cocoa has been with old projects that
originated prior to their introduction, so I haven't really been too
much into the bindings concept, which is why I'm trying to get myself
up to speed now, and pretty much teach myself how they work. With that
said, aren't bindings *always* creating a two-way connection between
properties? For example, say you have a generalized view like an
NSTextField. It's got a property called "stringValue" which is set via
the -stringValue and -setStringValue: methods. Sure, as a view, it's
rendering an object from my model on the screen, but at the same time
it's gotta store its data somewhere, because otherwise its drawRect:
method won't know what it should draw, and of course NSTextField can't
know about the objects in your model, because if it did, then it
wouldn't work with any other models and would lose its generalization,
working only with the specific model that existed in your application.
Now normally, an app would set the NSTextField's "stringValue"
property via the accessor methods, but now Bindings present us with a
new way to bind a property in the model with the "stringValue"
property in the NSTextField.
Or that's what I thought it was, anyway. If Bindings don't do that,
then I'm a little confused as to what they actually *do*.
In my case, what I have is a document object and a bunch of view
objects of a certain class. The view object's class wraps some
portable code that I didn't write, and basically provide some glue
between a portable C++ object and the Cocoa Obj-C system, with some
drawing methods on top to display the object. The view has a "title"
property set by the portable code (which my glue code bridges to the
setter method of the view object when the portable code wants to
change it). Usually the title is an independent property of the view
class, but for this one particular instance of that class I want to
bind it to my document's display name so that it will be the window's
title, but only for that particular instance, not for every instance
of the class. Now I could do that easily enough via notifications, and
that's what I would have done in 2004, when I still had to support
Jaguar, but part of the reason I'm trying to do this is because I'm
trying to teach myself about the "new" stuff (I realize the concept of
bindings is actually a few years old by now) so that I can get a grasp
of what it is, and how to use it. In actuality, there would be a few
more properties I'd want to bind later on, but first I need to know
exactly what is the difference between binding the title of a view
object to a variable in the model or controller, or doing the same
thing with the many bindable properties exposed by view objects in
Interface Builder, such as "Font" in an NSTextField, "Tool Tip" in a
button, or "Enabled" or "Hidden" in pretty much anything. There's
clearly some part of the concept I'm missing - but what is it?
Apologies for my long-winded post,
Charles -
On Jun 27, 2008, at 11:08 PM, Charles Srstka wrote:
> With that said, aren't bindings *always* creating a two-way
> connection between properties?
Not exactly, no. A binding is a different thing than a property.
(By the way, did you read the "How Do Bindings Work?" chapter I linked
to, or the earlier thread?)
> For example, say you have a generalized view like an NSTextField.
> It's got a property called "stringValue" which is set via the -
> stringValue and -setStringValue: methods. Sure, as a view, it's
> rendering an object from my model on the screen, but at the same
> time it's gotta store its data somewhere, because otherwise its
> drawRect: method won't know what it should draw, and of course
> NSTextField can't know about the objects in your model, because if
> it did, then it wouldn't work with any other models and would lose
> its generalization, working only with the specific model that
> existed in your application. Now normally, an app would set the
> NSTextField's "stringValue" property via the accessor methods, but
> now Bindings present us with a new way to bind a property in the
> model with the "stringValue" property in the NSTextField.
Actually, NSTextField does not have a binding named "stringValue",
even though it does have a property with that name. Conversely, it
has a binding called "value", although it doesn't have a property by
that name. See the NSTextField bindings reference: <http://developer.apple.com/documentation/Cocoa/Reference/CocoaBindingsRef/B
indingsText/NSTextField.html>.
What "has a binding called 'value'" means is described in that how-it-
works document. The NSTextField does use KVO to register itself as an
observer of the bound-to object and key path. However, what it does
with the notifications it receives because of that observation is
implementation dependent. In this case, if you think of it as though
it's keeping its stringValue property synced with the property named
by the key path you won't go too far wrong, but that's because that's
what NSTextField chooses to do with it. For your own view class, you
don't get that behavior automatically just by calling
bind:toObject:withKeyPath:options:. If that's the behavior you want,
you have to code it into your view class. In your original post, you
merely called bind:toObject:withKeyPath:options: and expected the two
properties to be synchronized.
By the way, it's far from obvious that binding an NSTextField's
"value" binding corresponds to syncing its "stringValue" property with
some other object's property. Note that NSTextField also has
doubleValue, intValue, and floatValue properties, not to mention tons
of other more-obviously-unrelated properties. Also note that, when
you set up the value binding of an NSTextField (either in IB or in
code), there's no opportunity to specify which of these properties is
to be kept in sync. That should tell you that there must be some
other "smarts" (i.e. code) involved. KVC and KVO are not sufficient,
although they are involved.
> Or that's what I thought it was, anyway. If Bindings don't do that,
> then I'm a little confused as to what they actually *do*.
They are for keeping views and models in sync without a lot of glue
code.
Now, of course views have internal state (whether it's exposed as
properties or not). And models also have state (usually accessible as
properties). So, it's not surprising that your conception of bindings
is that they just keep those two pieces of state in sync. However,
note that a view's state may not have a direct mapping to a model's
state and vice versa. Bindings are more general than just "connect
this model property to that view property, and that's that".
Bindings allow you to keep a _conceptual_ attribute of the view class
in sync with the model. The binding name names the conceptual
attribute. For example, NSTextField offers to allow you to bind its
"value" -- which is a conceptual attribute which doesn't directly
correspond to any property -- to an object and key path. How it
maintains that "value" attribute in response to changes in the named
property is custom to NSTextField. It doesn't just magically fall out
of KVC and KVO.
If you want your class to support a binding, you have to 1) identify
the conceptual attribute available for binding, 2) pick a name for
that conceptual attribute (which is in a different namespace than the
class's properties, and so may or may not match one), and 3) implement
the custom logic for how to map from that conceptual attribute to both
the class's internal state and the bound property of the other object.
Is that any clearer?
Regards,
Ken -
On Jun 28, 2008, at 1:00 AM, Ken Thomases wrote:
> Actually, NSTextField does not have a binding named "stringValue",> >.
> even though it does have a property with that name. Conversely, it
> has a binding called "value", although it doesn't have a property by
> that name. See the NSTextField bindings reference: <http://developer.apple.com/documentation/Cocoa/Reference/CocoaBindingsRef/B
indingsText/NSTextField.html
>
> What "has a binding called 'value'" means is described in that how-
> it-works document. The NSTextField does use KVO to register itself
> as an observer of the bound-to object and key path. However, what
> it does with the notifications it receives because of that
> observation is implementation dependent. In this case, if you think
> of it as though it's keeping its stringValue property synced with
> the property named by the key path you won't go too far wrong, but
> that's because that's what NSTextField chooses to do with it. For
> your own view class, you don't get that behavior automatically just
> by calling bind:toObject:withKeyPath:options:. If that's the
> behavior you want, you have to code it into your view class. In
> your original post, you merely called
> bind:toObject:withKeyPath:options: and expected the two properties
> to be synchronized.
>
> By the way, it's far from obvious that binding an NSTextField's
> "value" binding corresponds to syncing its "stringValue" property
> with some other object's property. Note that NSTextField also has
> doubleValue, intValue, and floatValue properties, not to mention
> tons of other more-obviously-unrelated properties. Also note that,
> when you set up the value binding of an NSTextField (either in IB or
> in code), there's no opportunity to specify which of these
> properties is to be kept in sync. That should tell you that there
> must be some other "smarts" (i.e. code) involved. KVC and KVO are
> not sufficient, although they are involved.
>
>
>> Or that's what I thought it was, anyway. If Bindings don't do that,
>> then I'm a little confused as to what they actually *do*.
>
> They are for keeping views and models in sync without a lot of glue
> code.
>
> Now, of course views have internal state (whether it's exposed as
> properties or not). And models also have state (usually accessible
> as properties). So, it's not surprising that your conception of
> bindings is that they just keep those two pieces of state in sync.
> However, note that a view's state may not have a direct mapping to a
> model's state and vice versa. Bindings are more general than just
> "connect this model property to that view property, and that's that".
>
> Bindings allow you to keep a _conceptual_ attribute of the view
> class in sync with the model. The binding name names the conceptual
> attribute. For example, NSTextField offers to allow you to bind its
> "value" -- which is a conceptual attribute which doesn't directly
> correspond to any property -- to an object and key path. How it
> maintains that "value" attribute in response to changes in the named
> property is custom to NSTextField. It doesn't just magically fall
> out of KVC and KVO.
>
> If you want your class to support a binding, you have to 1) identify
> the conceptual attribute available for binding, 2) pick a name for
> that conceptual attribute (which is in a different namespace than
> the class's properties, and so may or may not match one), and 3)
> implement the custom logic for how to map from that conceptual
> attribute to both the class's internal state and the bound property
> of the other object.
>
> Is that any clearer?
Hmm, you appear to be right. I'd forgotten that the text field's
actual binding was named "value". And no instance variable named
"value" appears to be implemented in NSTextField or any of its
superviews. Huh.
I guess the only question I still have then is: why did my example
worke one-way in the first place? If the bindings are in a different
namespace, shouldn't it have failed for lack of an exposed binding
named "title" in the Bar object? Or is there a *little* magic going on
here, just not going all the way?
I'd still prefer it if the system automatically provided support for
binding two properties to each other, for the cases where a property
*would* map one-to-one with the binding you wanted in the view (which
seems like it would have to happen quite frequently, especially for
the simpler bindings like font, color, enabled, etc.), while allowing
you to override that with custom code if needed. But at least now I'm
starting to feel like I'm beginning to understand how this thing
works, which is good. It's so frustrating when you're trying to work
with something that seems to be incomprehensible black magic.
Thanks,
Charles -
On Jun 28, 2008, at 1:30 AM, Charles Srstka wrote:
> I guess the only question I still have then is: why did my example
> worke one-way in the first place? If the bindings are in a different
> namespace, shouldn't it have failed for lack of an exposed binding
> named "title" in the Bar object? Or is there a *little* magic going
> on here, just not going all the way?
That depends on how the bar class from your OP (or one of its
superclasses) implemented bind:toObject:withKeyPath:options:. That
code may not have checked the passed-in binding name, and may have
unconditionally added itself as an observer of ivar_controller for the
key path "selection.displayName". That would have guaranteed that bar
would receive observeValueForKeyPath:ofObject:change:context: messages
whenever foo's displayName property was changed in a KVO-conforming
manner. (For example, if, in listing 2 of the how-it-works document,
the check of the binding name against "angle" were omitted.)
Then, what happens next is up to bar's implementation of
observeValueForKeyPath:ofObject:change:context:. If it blindly did
[self setTitle:[object valueForKeyPath:keyPath]], then that would
explain it. (For example, if, in listing 4, the test of context were
omitted.)
Regards,
ken -
On Jun 28, 2008, at 1:57 AM, Ken Thomases wrote:
> That depends on how the bar class from your OP (or one of its
> superclasses) implemented bind:toObject:withKeyPath:options:. That
> code may not have checked the passed-in binding name, and may have
> unconditionally added itself as an observer of ivar_controller for
> the key path "selection.displayName". That would have guaranteed
> that bar would receive
> observeValueForKeyPath:ofObject:change:context: messages whenever
> foo's displayName property was changed in a KVO-conforming manner.
> (For example, if, in listing 2 of the how-it-works document, the
> check of the binding name against "angle" were omitted.)
>
> Then, what happens next is up to bar's implementation of
> observeValueForKeyPath:ofObject:change:context:. If it blindly did
> [self setTitle:[object valueForKeyPath:keyPath]], then that would
> explain it. (For example, if, in listing 4, the test of context
> were omitted.)
The superclass would be NSView, which doesn't declare
bind:toObject:withKeyPath:options: in its header file, nor does
NSResponder, so it's likely NSObject's implementation, whatever it
does. Interestingly, NSObject's header file doesn't declare this as a
method either, although NSKeyValueBinding.h declares it as a category
on NSObject, which is apparently why the compiler doesn't complain.
Also interestingly, the only reference to the
bind:toObject:withKeyPath:options: method that comes up in an API
search of the documentation is from the NSKeyValueBindingCreation
protocol, which states this:
"Establishes a binding between a given property of the receiver and
the property of a given object specified by a given key path."
Since this doesn't seem to be actually the case, someone ought to file
a report on the documentation about this.
Oh well, thanks for your patience with my questions.
Charles -
On Jun 28, 2008, at 3:10 AM, Charles Srstka wrote:
> On Jun 28, 2008, at 1:57 AM, Ken Thomases wrote:
>
>> That depends on how the bar class from your OP (or one of its
>> superclasses) implemented bind:toObject:withKeyPath:options:. That
>> code may not have checked the passed-in binding name, and may have
>> unconditionally added itself as an observer of ivar_controller for
>> the key path "selection.displayName". That would have guaranteed
>> that bar would receive
>> observeValueForKeyPath:ofObject:change:context: messages whenever
>> foo's displayName property was changed in a KVO-conforming manner.
>> (For example, if, in listing 2 of the how-it-works document, the
>> check of the binding name against "angle" were omitted.)
>>
>> Then, what happens next is up to bar's implementation of
>> observeValueForKeyPath:ofObject:change:context:. If it blindly did
>> [self setTitle:[object valueForKeyPath:keyPath]], then that would
>> explain it. (For example, if, in listing 4, the test of context
>> were omitted.)
>
> The superclass would be NSView, which doesn't declare
> bind:toObject:withKeyPath:options: in its header file, nor does
> NSResponder, so it's likely NSObject's implementation, whatever it
> does. Interestingly, NSObject's header file doesn't declare this as
> a method either, although NSKeyValueBinding.h declares it as a
> category on NSObject, which is apparently why the compiler doesn't
> complain.
Yeah, it surprises me, too, that NSObject has an implementation of
bind:toObject:withKeyPath:options:. I had thought that it was just
part of an informal protocol -- that is, that it was declared in a
category on NSObject, but never implemented except by specific classes
which adopted that protocol. However, I did a symbol dump of the
AppKit framework and I see that there is, in fact, an implementation.
I have no idea what it could be doing.
> Also interestingly, the only reference to the
> bind:toObject:withKeyPath:options: method that comes up in an API
> search of the documentation is from the NSKeyValueBindingCreation
> protocol, which states this:
>
> "Establishes a binding between a given property of the receiver and
> the property of a given object specified by a given key path."
>
> Since this doesn't seem to be actually the case, someone ought to
> file a report on the documentation about this.
Yeah, and the description of the "binding" parameter of that method
also says it's a "key path for a property of the receiver", which
contradicts my understanding (as we've been discussing).
So, my curiosity piqued, I did some more reading. The "Bindings"
chapter of the Cocoa Fundamentals Guide <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals
/CommunicatingWithObjects/chapter_6_section_6.html> also directly contradicts what I've been saying. It unambiguously
states that you can bind together any two objects so long as they're
KVC/KVO-compliant. Now _I'm_ confused -- and worried that I've been
spreading misinformation.
Time to build a test project...
... time passes ...
OK. So, from what I can see, bindings do work with just KVC/KVO, but
they are inherently one-way. That is, the following:
[thing1 bind:@"property1" toObject:thing2
withKeyPath:@"property2" options:nil];
means that thing1's property1 should update itself with the value from
thing2's property2 whenever thing2's property2 changes. It does not
imply that thing2's property2 will be updated if thing1's property1
changes. If you want that, then you should set it up explicitly:
[thing2 bind:@"property2" toObject:thing1
withKeyPath:@"property1" options:nil];
From my brief testing, this does not produce infinitely looping
mutual updates.
However, it seems as though a binding name is _not_ a key path as
described in the documentation; it's just a key. Trying to use a key
path resulted in exceptions.
None of this jibes with bindings as they're used in views. First,
there's that reference listing the bindings supported by various
classes. As discussed, the list for NSTextField is decidedly shorter
than the list of properties for which NSTextField is KVC/KVO-
compliant. That's generally true of most views listed in that
reference. Second, establishing a binding to a view is two-way, while
establishing non-view bindings is one-way.
It's odd that there's no clear, definitive statement about what
happens when you bind the properties of two non-view, non-NSController-
derived classes together. As I said above, there is a definite
statement that you can do it, just not what happens if you do. The
fact that bind:toObject:withKeyPath:options: is only documented as
part of an informal protocol and not on NSObject itself implies that
there's no default implementation, and yet there is.
I'm quite perplexed.
> Oh well, thanks for your patience with my questions.
Thank you for your persistence in asking. It's helped me learn, or at
least unlearn. ;)
Cheers,
Ken -
On Jun 28, 2008, at 2:55 AM, Ken Thomases wrote:
>> > also directly contradicts what I've been saying. It unambiguously
>
>> Also interestingly, the only reference to the
>> bind:toObject:withKeyPath:options: method that comes up in an API
>> search of the documentation is from the NSKeyValueBindingCreation
>> protocol, which states this:
>>
>> "Establishes a binding between a given property of the receiver and
>> the property of a given object specified by a given key path."
>>
>> Since this doesn't seem to be actually the case, someone ought to
>> file a report on the documentation about this.
>
> Yeah, and the description of the "binding" parameter of that method
> also says it's a "key path for a property of the receiver", which
> contradicts my understanding (as we've been discussing).
>
> So, my curiosity piqued, I did some more reading. The "Bindings"
> chapter of the Cocoa Fundamentals Guide <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals
/CommunicatingWithObjects/chapter_6_section_6.html
> states that you can bind together any two objects so long as they're
> KVC/KVO-compliant. Now _I'm_ confused -- and worried that I've been
> spreading misinformation.
Note the terminology on that page:
" You can establish a binding between an attribute of a view object
and a property of a model object (typically through a mediating
property of a controller object)."
It refers to an "attribute", not a property or a key or key path. So I
am guessing that's the difference here: views override NSObject's
default property-based binding and replace it with an attribute-based
one. This allows two-way syncing to occur and prevents loops. Views,
since they allow the user to make changes, go the extra step of
propagating the change to the model as part of their binding
implementation. Regular non-view objects don't have this, so the
binding is one-way. They use KVC to see changes in the model value but
not to change the model value. Am I right?
[Stuff snipped]
>
> None of this jibes with bindings as they're used in views. First,
> there's that reference listing the bindings supported by various
> classes. As discussed, the list for NSTextField is decidedly
> shorter than the list of properties for which NSTextField is KVC/KVO-
> compliant. That's generally true of most views listed in that
> reference. Second, establishing a binding to a view is two-way,
> while establishing non-view bindings is one-way.
It's time for mmalc to chime in and put everyone straight.
Steve Weller <bagelturf...>
Technical Writing, Editing, Developer Guides, and a little Cocoa -
On Jun 28, 2008, at 4:55 AM, Ken Thomases wrote:
> Yeah, and the description of the "binding" parameter of that method> > also directly contradicts what I've been saying. It unambiguously
> also says it's a "key path for a property of the receiver", which
> contradicts my understanding (as we've been discussing).
>
> So, my curiosity piqued, I did some more reading. The "Bindings"
> chapter of the Cocoa Fundamentals Guide <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals
/CommunicatingWithObjects/chapter_6_section_6.html
> states that you can bind together any two objects so long as they're
> KVC/KVO-compliant. Now _I'm_ confused -- and worried that I've been
> spreading misinformation.
I wouldn't worry about that too much - everything you said seems to
jibe perfectly with what views do - the text field's binding *is*
called "value" and not "stringValue" (that was my bad), and there's no
corresponding "value" instance method on NSTextView nor any of its
superclasses, nor does running class-dump on the AppKit turn up a
"value" method on any class in the AppKit except for
_NSControllerKeyValuePair, whatever that is. So in the typical case of
views, you'd seem to be correct that the bindings represent something
other than properties, and live in a different namespace.
However, NSObject does have a default implementation of
bind:toObject:withKeyPath:options:, which must have some purpose.
Setting up a two-way binding by running the binding twice does seem to
work, although I don't know how "kosher" it is, and it does seem less
than satisfactory to me as, like you mentioned, it doesn't seem to
work with a key path for the first argument, making it necessary to
take the controller out of the equation. So it's definitely probably
better to override bind:toObject:withKeyPath:options: on the view, to
allow for using a controller and having a cleaner implementation.
After thinking about it a bit, though, I don't think infinite loops
should be a problem, because my guess as to how the bindings work is
that the willChangeValueForKey: method probably registers the object
somewhere as being in the middle of setting that key, and then when
the bindings system goes around looking for objects to set that key
for, it would pass over the ones that have indicated they're already
setting that key by calling willChangeValueForKey: I'd expect then
that didChangeValueForKey: would clear that status (along with asking
the bindings system to update any object that observes that key and
hasn't called willChangeValueForKey: recently). So infinite loops
shouldn't be much of a problem if I'm understanding this right.
I think what we can all take home from this is that the documentation
for bindings needs to be clearer and less self-contradictory on the
very basic concept of exactly what Cocoa Bindings *is*.
Charles -
On Jun 28, 2008, at 4:55 AM, Ken Thomases wrote:
> Yeah, it surprises me, too, that NSObject has an implementation of
> bind:toObject:withKeyPath:options:. I had thought that it was just
> part of an informal protocol -- that is, that it was declared in a
> category on NSObject, but never implemented except by specific
> classes which adopted that protocol. However, I did a symbol dump
> of the AppKit framework and I see that there is, in fact, an
> implementation. I have no idea what it could be doing.
Actually, I gave it a little thought, and perhaps the purpose of
NSObject's default implementation is just to make it easier to
implement the stuff that's mentioned in that "how bindings work"
document. The built-in implementation provides the bindings in one
direction for us - all we have to do is supply the bindings in the
other direction, so adding an NSMutableDictionary instance variable to
the view and then adding these methods:
- (void)bind:(NSString *)key toObject:(id)obj withKeyPath:(NSString
*)keyPath options:(NSDictionary *)options {
NSDictionary *binding = [NSDictionary
dictionaryWithObjectsAndKeys:key, @"key", obj, @"target", keyPath,
@"keyPath", nil];
[ivar_bindingsDict setObject:binding forKey:key];
[super bind:key toObject:obj withKeyPath:keyPath options:options];
}
- (void)unbind:(NSString *)key {
[ivar_bindingsDict removeObjectForKey:key];
}
- (void)fireNotificationsForKey:(NSString *)key {
NSDictionary *binding = [ivar_bindingsDict objectForKey:key];
if(binding) {
id target = [binding objectForKey:@"target"];
NSString *keyPath = [binding objectForKey:@"keyPath"];
[target setValue:[self valueForKey:key] forKeyPath:keyPath];
}
}
and then just calling [self fireNotificationsForKey:@"someKey"] each
time you modify whatever it is in the view's state that will cause the
binding "someKey" to need to be updated, would pretty much do it, am I
right?
(I suppose you'd also want to expose your available bindings by
calling +exposeBinding: in your +initialize method and implement
valueClassForBinding: if you're going to make an Interface Builder
palette for your view)
Charles -
On Jun 28, 2008, at 10:17 AM, Charles Srstka wrote:
> I think what we can all take home from this is that the
> documentation for bindings needs to be clearer and less self-
> contradictory on the very basic concept of exactly what Cocoa
> Bindings *is*.
For what it's worth, after sending my previous message, I did file a
documentation enhancement request using the "It's good, but" link.
Hopefully, I described my confusion and the several seemingly-
contradictory implications of the documentation well enough to be
useful to the good folks at Apple.
Cheers,
Ken -
On Sat, Jun 28, 2008 at 4:17 PM, Charles Srstka
<cocoadev...> wrote:
> I wouldn't worry about that too much - everything you said seems to jibe
> perfectly with what views do - the text field's binding *is* called "value"
> and not "stringValue" (that was my bad), and there's no corresponding
> "value" instance method on NSTextView nor any of its superclasses, nor does
> running class-dump on the AppKit turn up a "value" method on any class in
> the AppKit except for _NSControllerKeyValuePair, whatever that is. So in the
> typical case of views, you'd seem to be correct that the bindings represent
> something other than properties, and live in a different namespace.
And if you consider the relationship between the "value" binding and
the "objectValue" property, things get even more odd!
You can programmatically bind to an NSTextField's (and presumably any
other NSControl's) "objectValue" and achieve the same results as
binding to its "value" (either programmatically or through IB).
So you might think that NSControl has a "value" property, and simply
binds it to its own "objectValue" (or vice versa). Except that you
can't call "setValue" (or setValue:whatever forKey:@"value") on an
NSControl, as you would expect to be able to if this were the case.
Perhaps NSControls have their own bind:toObject:withKeyPath:options:
implementation which simply checks for "value" and effectively binds
to "objectValue"? No, classdump confirms that the only
bind:toObject:withKeyPath:options: implementation is that of the
NSKeyValueBindingCreation category of NSObject.
Maybe it's the NSObject implementation itself which handles the
special case? No, you can create an "objectValue" property on your own
classes but you still can't bind to "value" on them (the error message
complains "this class is not key value coding-compliant for the key
value")
It seems really wierd to me that this separate namespace exists,
especially as the AppKit designers could just have exposed the
"objectValue" binding directly rather than this "value" binding which
seems to do exactly the same thing...
Hamish -
On Jun 29, 2008, at 11:30 PM, Hamish Allan wrote:
> Perhaps NSControls have their own bind:toObject:withKeyPath:options:
> implementation which simply checks for "value" and effectively binds
> to "objectValue"? No, classdump confirms that the only
> bind:toObject:withKeyPath:options: implementation is that of the
> NSKeyValueBindingCreation category of NSObject.
Wait, what? Okay, that contradicts the understanding that I had come
to... so the built-in views establish two-way bindings *without*
overriding bind:toObject:withKeyPath:options:? Great, that puts us
back to square one!
Is there some way to page mmalc to this thread? I think his input
would be really helpful about now...
Charles -
On Mon, Jun 30, 2008 at 5:33 AM, Charles Srstka
<cocoadev...> wrote:
> Wait, what? Okay, that contradicts the understanding that I had come to...
> so the built-in views establish two-way bindings *without* overriding
> bind:toObject:withKeyPath:options:? Great, that puts us back to square one!
It would seem so, but in fact I was mistaken about the equivalence
between "value" and "objectValue" bindings: the binding to objectValue
is only a one-way binding. I guess that difference would make it safer
to use a separate namespace.
Hamish -
On Mon, Jun 30, 2008 at 12:38 AM, Hamish Allan <hamish...> wrote:
> On Mon, Jun 30, 2008 at 5:33 AM, Charles Srstka
> <cocoadev...> wrote:
>
>> Wait, what? Okay, that contradicts the understanding that I had come to...
>> so the built-in views establish two-way bindings *without* overriding
>> bind:toObject:withKeyPath:options:? Great, that puts us back to square one!
>
> It would seem so, but in fact I was mistaken about the equivalence
> between "value" and "objectValue" bindings: the binding to objectValue
> is only a one-way binding. I guess that difference would make it safer
> to use a separate namespace.
I am largely bindings clueless, so beware....
NSObject's -bind:... method does two things. First, it sets up an
automatic one-way binding from the model object to the view object.
When the model is changed, the view's key is automatically set to the
new value. Second, it sets up an info dictionary for that binding.
Although Apple's sample code shows overriding -bind:... to store
information about the new binding, it doesn't look like this is
necessary. You can simply use -infoForBinding: to obtain the info
dictionary, extract the bound object and key, and use that information
to update the model object. I'd assume this is what the Apple classes
do, and it seems to me to be a lot simpler than overriding -bind:...
to stash away a bunch of information that's already being stored for
you anyway.
The reason the objectValue binding doesn't work both ways is because
NSControl doesn't implement this kind of thing when its objectValue
changes. You need to implement the view->model changes manually they
don't come for free just because you're KVC compliant, and NSControl
doesn't implement it for objectValue. You get the model->view
direction for free with KVC complaince, which is why it halfway works.
Mike -
On Mon, Jun 30, 2008 at 3:56 PM, Michael Ash <michael.ash...> wrote:
> Although Apple's sample code shows overriding -bind:... to store
> information about the new binding, it doesn't look like this is
> necessary. You can simply use -infoForBinding: to obtain the info
> dictionary, extract the bound object and key, and use that information
> to update the model object. I'd assume this is what the Apple classes
> do, and it seems to me to be a lot simpler than overriding -bind:...
> to stash away a bunch of information that's already being stored for
> you anyway.
That would seem a pretty reasonable assumption, but it doesn't seem to
be the case. At least, breakpoints on -[NSTextField infoForBinding:],
-[NSControl infoForBinding:], -[NSObject infoForBinding:] don't seem
to trigger when the text field is edited; nor are messages logged from
a subclass of NSTextField overriding -infoForBinding:.
Any other ideas, anyone?
Thanks,
Hamish -
Sorry, I haven't read every message in this thread, but I think I can
answer the original question
> [[self bar] bind:@"title" toObject:ivar_controller
> withKeyPath:@"selection.displayName" options:nil];
>
> Now here's the thing: if I call setDisplayName: on Foo, it calls
> Bar's setTitle: method, exactly as it should. However, if I call
> setTitle: on Bar, it does *not* end up calling Foo's setDisplayName:
> method, although it seems like it should. I can change the
> bind:toObject:withKeyPath:options: invocation above so that it binds
> Bar directly to Foo without going through the object controller, or
> I can try going the other way and binding the Foo to the Bar -
> always I get the same result.
Bindings of this type are one way. Their kinda ad hoc. "Title" will be
updated to match ivar_controller.selection.displayName. Changing title
will not result in any KVC calls to change anything in the
ivar_controller. This is a read-only setup.
It sounds like you're asking for 2 things.
1) To have logic that will update ivarController.selection.displayName
to match "title".
2) To have the logic from #1 triggered when setTitle is called.
There was some suggestion about using infoForBinding: to do blah blah
blah.
Yes! infoForBinding is what you should use to implement the logic in #1.
// in Bar get the infoForBinding dictionary
NSDictionary *info = [self infoForBinding:@"title"];
// extract the controller and keypath info
id controller = [info objectForKey:NSObservedObjectKey];
NSString *keyPath = [info objectForKey:NSObservedKeyPathKey];
// extra points for looking in the binding options for value
transformers and stuff
// options = [info objectForKey:NSOptionsKey];
// push/write the value to the controller
[controller setValue:theTitle forKeyPath:keyPath];
The trick to getting #2 is that setTitle is ALSO what gets called
during the regular we-did-the-read-work-for-you bindings update from
the controller. Don't let changing the displayName end up calling
setTitle if setTitle's going to set the displayName. Make sense?
So how do we fix this issue?
2a) Don't use setTitle to trigger logic in #1. This is the approach I
normally suggest. Your views should push these changes down due to
user interaction, not programatic fiddling.
2b) Implement the "read" logic yourself by implementing bind:. This
means you'll need to cache the binding info yourself, start observing
the controller object, and react to the KVO notifications
appropriately. Don't call super for bind:/unbind:/infoForBinding:
@"title".
As a final note - I'm not sure if anyone else mentioned it. The
original code snippets had stuff like
- (void)setTitle:(NSString *)title {
[self willChangeValueForKey:@"title"];
NSLog(@"setting title to %@", title);
if(title != ivar_title) {
[ivar_title release];
ivar_title = [title copy];
}
[self didChangeValueForKey:@"title"];
}
You don't need the will/did changeValueForKey:@"title" calls in the
setTitle: method if you haven't disabled automatic KVO notifications
for title. If you didn't know you could do that, then you haven't
disabled KVO notifications for your class and, therefore, don't need
to call will/did changeValueForKey:@"title".
Hope that clears things up.
On Jun 30, 2008, at 2:04 PM, Hamish Allan wrote:
> On Mon, Jun 30, 2008 at 3:56 PM, Michael Ash <michael.ash...>
> wrote:
>
>> Although Apple's sample code shows overriding -bind:... to store
>> information about the new binding, it doesn't look like this is
>> necessary. You can simply use -infoForBinding: to obtain the info
>> dictionary, extract the bound object and key, and use that
>> information
>> to update the model object. I'd assume this is what the Apple classes
>> do, and it seems to me to be a lot simpler than overriding -bind:...
>> to stash away a bunch of information that's already being stored for
>> you anyway.
>
> That would seem a pretty reasonable assumption, but it doesn't seem to
> be the case. At least, breakpoints on -[NSTextField infoForBinding:],
> -[NSControl infoForBinding:], -[NSObject infoForBinding:] don't seem
> to trigger when the text field is edited; nor are messages logged from
> a subclass of NSTextField overriding -infoForBinding:.
>
> Any other ideas, anyone?
>
> Thanks,
> Hamish
--------------------------
RONZILLA -
On Mon, Jun 30, 2008 at 10:43 PM, Ron Lue-Sang <luesang...> wrote:
> Yes! infoForBinding is what you should use to implement the logic in #1.
> [...]
> 2b) Implement the "read" logic yourself by implementing bind:.
What puzzles me is that NSTextField doesn't seem to do either of
these, yet still seems to know which key path to update after user
interaction.
Hamish -
On Mon, Jun 30, 2008 at 5:04 PM, Hamish Allan <hamish...> wrote:
> On Mon, Jun 30, 2008 at 3:56 PM, Michael Ash <michael.ash...> wrote:
>
>> Although Apple's sample code shows overriding -bind:... to store
>> information about the new binding, it doesn't look like this is
>> necessary. You can simply use -infoForBinding: to obtain the info
>> dictionary, extract the bound object and key, and use that information
>> to update the model object. I'd assume this is what the Apple classes
>> do, and it seems to me to be a lot simpler than overriding -bind:...
>> to stash away a bunch of information that's already being stored for
>> you anyway.
>
> That would seem a pretty reasonable assumption, but it doesn't seem to
> be the case. At least, breakpoints on -[NSTextField infoForBinding:],
> -[NSControl infoForBinding:], -[NSObject infoForBinding:] don't seem
> to trigger when the text field is edited; nor are messages logged from
> a subclass of NSTextField overriding -infoForBinding:.
>
> Any other ideas, anyone?
Well, this is irrelevant to the question of what *you* should do.
Using -infoForBinding: is simple and it works, so use it.
However, if you're curious about what Apple does, it shouldn't be too
hard to find out. You know one thing that happens reliably: your
model's key is set. So set up a test app, put a breakpoint on the
model's setter, then see what's calling it. The rest should follow
from there.
Mike -
On Jun 30, 2008, at 2:53 PM, Hamish Allan wrote:
> On Mon, Jun 30, 2008 at 10:43 PM, Ron Lue-Sang <luesang...>
> wrote:
>
>> Yes! infoForBinding is what you should use to implement the logic
>> in #1.
>> [...]
>> 2b) Implement the "read" logic yourself by implementing bind:.
>
> What puzzles me is that NSTextField doesn't seem to do either of
> these, yet still seems to know which key path to update after user
> interaction.
>
> Hamish
Yep, that's right. The bindings machinery uses a faster cache. The
same way as bindable-view implementors are free to cache the binding
information any way you like. You don't need to use infoForBinding,
but it's the easiest solution to describe.
--------------------------
RONZILLA -
On Tue, Jul 1, 2008 at 12:56 AM, Michael Ash <michael.ash...> wrote:
> However, if you're curious about what Apple does, it shouldn't be too
> hard to find out. You know one thing that happens reliably: your
> model's key is set. So set up a test app, put a breakpoint on the
> model's setter, then see what's calling it. The rest should follow
> from there.
This gets you into a whole world of wondering why _NSBindingAdapter,
NSValueBinder, NSBinder etc. exist. I think I'll leave that for now!
I do wonder, incidentally, why the NSKeyValueBindingCreation category
of NSObject is in AppKit rather than Foundation.
Hamish -
Hi,
Regarding the whole asymmetry between the one-way bindings between
arbitrary KVC/KVO-compliant properties on the one hand and the two-way
bindings supported by views and NSController-derived objects on the
other hand, I think I figured something out.
The documentation makes, in a few places, a distinction between the
terms "key-value bindings" (KVB) and "Cocoa bindings". In fact, Cocoa
bindings are described as being built on KVC, KVO, _and KVB_:
From "What Are Cocoa Bindings?" <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Con
cepts/WhatAreBindings.html>:
> [This article] gives a conceptual overview of how the main
> technologies that underpin Cocoa bindings—key-value coding, key-
> value observing, and key-value binding—work, and how they inter-
> relate.
From "How Do Bindings Work?" <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Con
cepts/HowDoBindingsWork.html>:
> Cocoa bindings rely on other technologies—key-value coding (KVC) and
> key-value observing (KVO)—to communicate changes between objects,
> and on key-value binding (KVB) to bind a value in one object to a
> property in another.
From "Cocoa Fundamentals Guide: Bindings" <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals
/CommunicatingWithObjects/chapter_6_section_6.html>:
> The implementation of bindings rests on the enabling mechanisms of
> key-value coding, key-value observing, and key-value binding.
So, it seems like my confusion was in thinking there was only one kind
of binding supported by Cocoa, when there are two which are
confusingly-similarly-named. Adding to the confusion is that the
documentation tends to refer to "binding(s)" with neither prefix, and
which it means is not always clear from the context.
KVB is a generic capability that you get with the
bind:toObject:withKeyPath:options: method for most classes. It is one-
way updating of a KVC-compliant property on the receiver from a KVC/
KVO-compliant property at the key-path from the named object.
In addition, some framework classes supply additional functionality on
top of that -- Cocoa bindings. The functioning of this kind of
binding is radically different, even though it still uses
bind:toObject:withKeyPath:options: as its interface. As discussed,
the name of a Cocoa binding need not be a property of the receiver.
(It's often referred to as an "attribute".) Also, it's two-way.
I think this subtle distinction in terminology needs to be called out
more forcefully in the documentation. Also, there should be
documentation on NSObject as to what
bind:toObject:withKeyPath:options: does in its default implementation
(one-way property update), and possibly separate documentation on
NSView and NSController about the separate behavior that those classes
provide for the same method. The fact that that method is currently
only documented on an informal protocol is misleading. It suggested
(at least to me) that there was no default implementation, and one had
to override it as illustrated in "How Do Bindings Work?" for it to do
anything at all. I did eventually find this:
From "NSKeyValueBindingCreation Protocol Reference" <http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Pro
tocols/NSKeyValueBindingCreation_Protocol/>:
> This informal protocol is implemented by NSObject and its methods
> can be overridden by view and controller subclasses.
but that leaves a lot unsaid.
Cheers,
Ken -
Key value Binding and Cocoa Bindings are the same thing.
Key-Value Binding is implemented at the foundation level. Cocoa
Bindings is the name used for the additional features (controllers,
views that support bindings, etc..) which is implemented at the AppKit
level.
So there is no distinction.
On Jul 2, 2008, at 5:14 AM, Ken Thomases wrote:
> Hi,> >:
>
> Regarding the whole asymmetry between the one-way bindings between
> arbitrary KVC/KVO-compliant properties on the one hand and the two-
> way bindings supported by views and NSController-derived objects on
> the other hand, I think I figured something out.
>
> The documentation makes, in a few places, a distinction between the
> terms "key-value bindings" (KVB) and "Cocoa bindings". In fact,
> Cocoa bindings are described as being built on KVC, KVO, _and KVB_:
>
> From "What Are Cocoa Bindings?" <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Con
cepts/WhatAreBindings.html
>> >:
>> [This article] gives a conceptual overview of how the main
>> technologies that underpin Cocoa bindings—key-value coding, key-
>> value observing, and key-value binding—work, and how they inter-
>> relate.
>
>
> From "How Do Bindings Work?" <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Con
cepts/HowDoBindingsWork.html
>> >:
>> Cocoa bindings rely on other technologies—key-value coding (KVC)
>> and key-value observing (KVO)—to communicate changes between
>> objects, and on key-value binding (KVB) to bind a value in one
>> object to a property in another.
>
> From "Cocoa Fundamentals Guide: Bindings" <http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals
/CommunicatingWithObjects/chapter_6_section_6.html
>> >:
>> The implementation of bindings rests on the enabling mechanisms of
>> key-value coding, key-value observing, and key-value binding.
>
>
> So, it seems like my confusion was in thinking there was only one
> kind of binding supported by Cocoa, when there are two which are
> confusingly-similarly-named. Adding to the confusion is that the
> documentation tends to refer to "binding(s)" with neither prefix,
> and which it means is not always clear from the context.
>
> KVB is a generic capability that you get with the
> bind:toObject:withKeyPath:options: method for most classes. It is
> one-way updating of a KVC-compliant property on the receiver from a
> KVC/KVO-compliant property at the key-path from the named object.
>
> In addition, some framework classes supply additional functionality
> on top of that -- Cocoa bindings. The functioning of this kind of
> binding is radically different, even though it still uses
> bind:toObject:withKeyPath:options: as its interface. As discussed,
> the name of a Cocoa binding need not be a property of the receiver.
> (It's often referred to as an "attribute".) Also, it's two-way.
>
>
> I think this subtle distinction in terminology needs to be called
> out more forcefully in the documentation. Also, there should be
> documentation on NSObject as to what
> bind:toObject:withKeyPath:options: does in its default
> implementation (one-way property update), and possibly separate
> documentation on NSView and NSController about the separate behavior
> that those classes provide for the same method. The fact that that
> method is currently only documented on an informal protocol is
> misleading. It suggested (at least to me) that there was no default
> implementation, and one had to override it as illustrated in "How Do
> Bindings Work?" for it to do anything at all. I did eventually find
> this:
>
> From "NSKeyValueBindingCreation Protocol Reference" <http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Pro
tocols/NSKeyValueBindingCreation_Protocol/
>
>> This informal protocol is implemented by NSObject and its methods
>> can be overridden by view and controller subclasses.
>
> but that leaves a lot unsaid.
>
> Cheers,
> Ken
-
On Wed, Jul 2, 2008 at 5:31 PM, Scott Anguish <scott...> wrote:
> Key value Binding and Cocoa Bindings are the same thing.
>
> Key-Value Binding is implemented at the foundation level. Cocoa Bindings is
> the name used for the additional features (controllers, views that support
> bindings, etc..) which is implemented at the AppKit level.
>
> So there is no distinction.
This is a rather unuseful attitude to take. Clearly, this thread
started as a result of the distinction. Also, Apple's own
documentation disagrees with you, as it states that Cocoa bindings are
built on KVB. Ken's synopsis is right on the mark. I'd go even further
and say that two-way binding ought to use a separate selector to make
the distinction clear. There is already *far too much* hidden magic in
bindings.
Furthermore, bind:toObject:withKeyPath:options: is implemented in a
category of NSObject in AppKit.framework, not at the Foundation level.
I agree with you that it should be in the latter, though!
Hamish -
On Jul 2, 2008, at 4:04 PM, Hamish Allan wrote:
> This is a rather unuseful attitude to take. Clearly, this threadNo, it doesn't.
> started as a result of the distinction. Also, Apple's own
> documentation disagrees with you, as it states that Cocoa bindings are
> built on KVB.
>
"Cocoa bindings" is an abstract term that refers to a collection of
technologies that used together keep views, controllers, and models
synchronised.
Key-value binding is one of those technologies.
There are not "two different kinds of binding".
mmalc -
On Jul 2, 2008, at 7:04 PM, Hamish Allan wrote:
> On Wed, Jul 2, 2008 at 5:31 PM, Scott Anguish <scott...>
> wrote:
>
>> Key value Binding and Cocoa Bindings are the same thing.
>>
>> Key-Value Binding is implemented at the foundation level. Cocoa
>> Bindings is
>> the name used for the additional features (controllers, views that
>> support
>> bindings, etc..) which is implemented at the AppKit level.
>>
>> So there is no distinction.
>
> This is a rather unuseful attitude to take. Clearly, this thread
> started as a result of the distinction.
It may have started from that, but there is no distinction. they are
the same technology. KVB is the protocol, Cocoa Bindings is the term
used to describe the complete set of features, including the
controller and view objects.
> Also, Apple's own
> documentation disagrees with you, as it states that Cocoa bindings are
> built on KVB.
It was never intended to even hint that they were separate things.
They are one and the same.
<excerpt>
The NSKeyValueBindingCreation informal protocol provides methods to
create and remove bindings between view objects and controllers or
controllers and model objects. In addition, it provides a means for a
view subclass to advertise the bindings that it exposes. This informal
protocol is implemented by NSObject and its methods can be overridden
by view and controller subclasses.
</excerpt>
Binding directly between objects other than those was at the time that
was written (and IMHO should still be) discouraged. There is still
difference of opinion on whether that should be the case.
> Ken's synopsis is right on the mark. I'd go even further
> and say that two-way binding ought to use a separate selector to make
> the distinction clear. There is already *far too much* hidden magic in
> bindings.
>
> Furthermore, bind:toObject:withKeyPath:options: is implemented in a
> category of NSObject in AppKit.framework, not at the Foundation level.
> I agree with you that it should be in the latter, though!
Yes, I screwed this up and immediately realized it when I was away
from the machine. -
On Thu, Jul 3, 2008 at 1:12 AM, mmalc crawford <mmalc_lists...> wrote:
>
> On Jul 2, 2008, at 4:04 PM, Hamish Allan wrote:
>
>> This is a rather unuseful attitude to take. Clearly, this thread
>> started as a result of the distinction. Also, Apple's own
>> documentation disagrees with you, as it states that Cocoa bindings are
>> built on KVB.
>>
> No, it doesn't.
No, really, it does! Read Ken's post again: he links to docs that talk
of Cocoa bindings "relying on" KVB, and KVB being one of the main
technologies "underpinning" Cocoa bindings. You yourself make pretty
much the same distinction:
> "Cocoa bindings" is an abstract term that refers to a collection of
> technologies that used together keep views, controllers, and models
> synchronised.
> Key-value binding is one of those technologies.
> There are not "two different kinds of binding".
If that is the case, let me ask: is KVB unidirectional or bi-directional?
Hamish -
On Jul 7, 2008, at 3:51 PM, Hamish Allan wrote:
> If that is the case, let me ask: is KVB unidirectional or bi-
> directional?
Whether a binding is unidirectional or bidirectional depends upon the
specific binding in question and the meaning the class providing it
has decided to give it.
-- Chris -
*sigh*
I haven't looked at these docs recently. With that in mind, here's how
I think of things…
YES: Cocoa Bindings ®™ is built on KVC, KVO and KVB
KVB is an informal protocol. So Cocoa Bindings™® provides a concrete
implementation (on NSObject) of the KVB protocols.
In addition to providing a KVB implementation, Cocoa Bindings®™ adds a
set of reusable controllers to Cocoa.
None of this really matters if you ask me. Did you ask me?
The NSKeyValueBindingCreation protocol itself doesn't explicitly
specify whether bindings are unidirectional or bidirectional. Many of
the bindings implemented by Cocoa Bindings®™ are implemented for
specific Cocoa views (and the Cocoa Bindings®™ provided controllers).
Many of these bindings happen to be bi-directional. Yay.
Cocoa Binding™® also happens to provide a super generic implementation
of NSKeyValueBindingCreation protocols so that even if you bind
something that isn't "exposed" as a binding (like, you wouldn't see it
in the object's exposedBindings list), something useful still happens.
Are there two different kinds of bindings? Without getting too
philosophical, I don't think there are. Hamish, what are the two types
you're thinking of?
On Jul 7, 2008, at 3:51 PM, Hamish Allan wrote:
> On Thu, Jul 3, 2008 at 1:12 AM, mmalc crawford <mmalc_lists...>
> wrote:
>>
>> On Jul 2, 2008, at 4:04 PM, Hamish Allan wrote:
>>
>>> This is a rather unuseful attitude to take. Clearly, this thread
>>> started as a result of the distinction. Also, Apple's own
>>> documentation disagrees with you, as it states that Cocoa bindings
>>> are
>>> built on KVB.
>>>
>> No, it doesn't.
>
> No, really, it does! Read Ken's post again: he links to docs that talk
> of Cocoa bindings "relying on" KVB, and KVB being one of the main
> technologies "underpinning" Cocoa bindings. You yourself make pretty
> much the same distinction:
>
>> "Cocoa bindings" is an abstract term that refers to a collection of
>> technologies that used together keep views, controllers, and models
>> synchronised.
>> Key-value binding is one of those technologies.
>
>> There are not "two different kinds of binding".
>
> If that is the case, let me ask: is KVB unidirectional or bi-
> directional?
>
> Hamish
--------------------------
RONZILLA -
If you feel that the bindings doc is unclear about this, thats one
thing to claim, and something to file a bug about. I can't guarantee
that it'll change though. I've never heard the argument that we have
two different types of bindings before this thread.
but if you're arguing with mmalc and I that we don't know what the doc
says, I can assure you we both do.
It's now been explained that we don't have two different types of
bindings by the people who wrote that doc, and one of the engineers
that works on the implementation.
I'm unsure why this thread even started up again.
On Jul 7, 2008, at 6:51 PM, Hamish Allan wrote:
> On Thu, Jul 3, 2008 at 1:12 AM, mmalc crawford <mmalc_lists...>
> wrote:
>>
>> On Jul 2, 2008, at 4:04 PM, Hamish Allan wrote:
>>
>>> This is a rather unuseful attitude to take. Clearly, this thread
>>> started as a result of the distinction. Also, Apple's own
>>> documentation disagrees with you, as it states that Cocoa bindings
>>> are
>>> built on KVB.
>>>
>> No, it doesn't.
>
> No, really, it does! Read Ken's post again: he links to docs that talk
> of Cocoa bindings "relying on" KVB, and KVB being one of the main
> technologies "underpinning" Cocoa bindings. You yourself make pretty
> much the same distinction:
-
On Tue, Jul 8, 2008 at 5:29 AM, Ron Lue-Sang <luesang...> wrote:
> KVB is an informal protocol. So Cocoa Bindings™(R) provides a concrete
> implementation (on NSObject) of the KVB protocols.
> In addition to providing a KVB implementation, Cocoa Bindings(R)™ adds a set
> of reusable controllers to Cocoa.
The penny drops! Thank you, Ron.
The docs (http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Con
cepts/WhatAreBindings.html),
in answer to the question "What Is A Binding?", state that "a binding
is an attribute of one object that may be bound to a property in
another such that a change in either one is reflected in the other."
But there is also another type of binding, which I have since found
referred to in the docs as "Read-Only"
(http://developer.apple.com/documentation/Cocoa/Reference/CocoaBindingsRef/C
oncepts/BindingTypes.html),
in which the change is only reflected in one direction. NSObject
provides an implementation of this, which I had previously thought of
as a "pure" key-value binding, whereas I thought of the description
above as referring to "Cocoa bindings" (partly because if I were
writing the two-way implementation, I would build it atop the
unidirectional implementation, just as the docs state that Cocoa
Bindings are built on KVB). But I now understand that both types of
bindings are actually Cocoa Bindings.
Scott, for what it's worth, I really don't agree with you that Cocoa
Bindings and KVB are "the same thing" or that "there is no
distinction". I now understand that they are not two different types
of bindings: indeed, that neither of them is a type of binding. But if
you're wondering why this thread has gone on for longer than it should
have done, it's partly because your repeated assertion of their
equivalence has drawn my attention away from what your colleagues have
been trying to point out to me: that KVB is merely the informal
protocol, whereas the various implementations (and what I would call
"types" of binding) are all provided by Cocoa Bindings(R)™.
Thank you also to everyone else who replied.
Hamish -
On Jul 8, 2008, at 11:33 AM, Hamish Allan wrote:
> Scott, for what it's worth, I really don't agree with you that Cocoa
> Bindings and KVB are "the same thing" or that "there is no
> distinction".
Ron just said the same thing.
> I now understand that they are not two different types
> of bindings: indeed, that neither of them is a type of binding. But if
> you're wondering why this thread has gone on for longer than it should
> have done, it's partly because your repeated assertion of their
> equivalence has drawn my attention away from what your colleagues have
> been trying to point out to me: that KVB is merely the informal
> protocol, whereas the various implementations (and what I would call
> "types" of binding) are all provided by Cocoa Bindings(R)™.
>
I think it was the first response I made in this thread I quoted the
NSKeyValueBindingCreation protocol reference doc, which says, in its
first paragraph:
The NSKeyValueBindingCreation __informal protocol__ provides methods
to create and remove bindings between view objects and controllers or
controllers and model objects. In addition, it provides a means for a
view subclass to advertise the bindings that it exposes. This informal
protocol is implemented by NSObject and its methods can be overridden
by view and controller subclasses.
Everything Ron said is right there in that paragraph.
I don't understand how anything I've said could draw your attention
away from anything mmalc or Ron said. We've all been repeating the
same thing. -
On Wed, Jul 9, 2008 at 2:43 AM, Scott Anguish <scott...> wrote:
>
> On Jul 8, 2008, at 11:33 AM, Hamish Allan wrote:
>
>> Scott, for what it's worth, I really don't agree with you that Cocoa
>> Bindings and KVB are "the same thing" or that "there is no
>> distinction".
>
> Ron just said the same thing.
If you honestly think that an informal protocol and its implementation
are the same thing, and that X and a proper subset of X are the same
thing, then I can see how you might arrive at that conclusion.
Otherwise, I am baffled.
> Everything Ron said is right there in that paragraph.
How can you say that, when it doesn't even mention Cocoa Bindings?
> I don't understand how anything I've said could draw your attention away
> from anything mmalc or Ron said. We've all been repeating the same thing.
No. Specifically, neither of them have ever claimed that Cocoa
Bindings and KVB are the same thing.
Hamish -
On Jul 8, 2008, at 9:39 PM, Hamish Allan wrote:
> On Wed, Jul 9, 2008 at 2:43 AM, Scott Anguish <scott...>
> wrote:
>>
>> On Jul 8, 2008, at 11:33 AM, Hamish Allan wrote:
>>
>>> Scott, for what it's worth, I really don't agree with you that Cocoa
>>> Bindings and KVB are "the same thing" or that "there is no
>>> distinction".
>>
>> Ron just said the same thing.
>
> If you honestly think that an informal protocol and its implementation
> are the same thing, and that X and a proper subset of X are the same
> thing, then I can see how you might arrive at that conclusion.
> Otherwise, I am baffled.
>
>> Everything Ron said is right there in that paragraph.
>
> How can you say that, when it doesn't even mention Cocoa Bindings?
>
>> I don't understand how anything I've said could draw your attention
>> away
>> from anything mmalc or Ron said. We've all been repeating the same
>> thing.
>
> No. Specifically, neither of them have ever claimed that Cocoa
> Bindings and KVB are the same thing.
>
This has gone too far -- you're monstrously misrepresenting what Scott
wrote.
On Jul 8, 2008, at 8:33 AM, Hamish Allan wrote:
> But if you're wondering why this thread has gone on for longer thanBefore Scott posted his first, this thread had 25 messages whose
> it should
> have done, it's partly because your repeated assertion of their
> equivalence has drawn my attention away from what your colleagues have
> been trying to point out to me: that KVB is merely the informal
> protocol, whereas the various implementations (and what I would call
> "types" of binding) are all provided by Cocoa Bindings(R)™.
>
content could perhaps be most charitably equated to a debate about the
number of angels that could fit on a pinhead. It culminated in this
bizarre assertion that there were *two types of binding*:
On Jul 2, 2008, at 5:14 AM, Ken Thomases wrote:
> Regarding the whole asymmetry between the one-way bindings between
> arbitrary KVC/KVO-compliant properties on the one hand and the two-
> way bindings supported by views and NSController-derived objects on
> the other hand, I think I figured something out.
> The documentation makes, in a few places, a distinction between the
> terms "key-value bindings" (KVB) and "Cocoa bindings". In fact,
> Cocoa bindings are described as being built on KVC, KVO, _and KVB_:
>
[...]
>
> So, it seems like my confusion was in thinking there was only one
> kind of binding supported by Cocoa, when there are two which are
> confusingly-similarly-named. Adding to the confusion is that the
> documentation tends to refer to "binding(s)" with neither prefix,
> and which it means is not always clear from the context.
>
> KVB is a generic capability that you get with the
> bind:toObject:withKeyPath:options: method for most classes. It is
> one-way updating of a KVC-compliant property on the receiver from a
> KVC/KVO-compliant property at the key-path from the named object.
>
> In addition, some framework classes supply additional functionality
> on top of that -- Cocoa bindings. The functioning of this kind of
> binding is radically different, even though it still uses
> bind:toObject:withKeyPath:options: as its interface. As discussed,
> the name of a Cocoa binding need not be a property of the receiver.
> (It's often referred to as an "attribute".) Also, it's two-way.
and it was to this that Scott replied:
> Key value Binding and Cocoa Bindings are the same thing.
> Key-Value Binding is implemented at the foundation level.[sic --
> Scott admitted the error later, but it's not relevant to the
> issue.] Cocoa Bindings is the name used for the additional features
> (controllers, views that support bindings, etc..) which is
> implemented at the AppKit level.
> So there is no distinction.
Note in particular the middle sentences: These make precisely the same
point that Ron and I have made, and that you're asserting Scott did not.
Scott later repeated the same point:
On Jul 2, 2008, at 5:13 PM, Scott Anguish wrote:
> It may have started from that, but there is no distinction. they are
> the same technology. KVB is the protocol, Cocoa Bindings is the
> term used to describe the complete set of features, including the
> controller and view objects.
>
Scott further made the context -- Ken's original flawed analysis --
clear:
On Jul 8, 2008, at 3:11 AM, Scott Anguish wrote:
> It's now been explained that we don't have two different types of
> bindings by the people who wrote that doc, and one of the engineers
> that works on the implementation.
>
So, apropos of:
> If you honestly think that an informal protocol and its implementationScott has never made either claim.
> are the same thing, and that X and a proper subset of X are the same
> thing, then I can see how you might arrive at that conclusion.
> [...]
> No. Specifically, neither of them have ever claimed that Cocoa
> Bindings and KVB are the same thing.
>
This thread has now run way past any conceivable utility it may have
had; if you have any further comments, and in particular any further
ad hominems against Scott, *please take them off-list*.
mmalc -
On Jul 9, 2008, at 12:39 AM, Hamish Allan wrote:
> On Wed, Jul 9, 2008 at 2:43 AM, Scott Anguish <scott...>
> wrote:
>>
>> On Jul 8, 2008, at 11:33 AM, Hamish Allan wrote:
>>
>>> Scott, for what it's worth, I really don't agree with you that Cocoa
>>> Bindings and KVB are "the same thing" or that "there is no
>>> distinction".
>>
>> Ron just said the same thing.
>
> If you honestly think that an informal protocol and its implementation
> are the same thing, and that X and a proper subset of X are the same
> thing, then I can see how you might arrive at that conclusion.
> Otherwise, I am baffled.
>
This is a misrepresentation (yet again). To go back to the point where
this all started.
There are not two different bindings technologies with confusingly
similar names (Cocoa Bindings and Key-Value Binding).
There is one, it's all Cocoa Bindings.
and now I'm going to pull out the moderator hammer and close the thread. -
In subsequent discussion off-list, Mmalc has made it known to me that
in questioning Scott's statements that Key-Value Binding and Cocoa
Bindings are the same thing -- or rather, in failing to capitulate to
his insistence that Ron made the identical claim -- I have caused him
considerable physical and mental distress, undermined his character,
brought him into disrepute, defamed him, devalued him, and damaged
him; and that my behaviour was inexcusable, contemptible,
reprehensible and truly obnoxious.
I had no idea that it was possible to cause such calamity to a
person's reputation simply by disagreeing with them in a public forum;
let alone to cause them physical distress by doing so. I must
therefore apologise for this, and implore anyone reading the thread to
allay mmalc's concerns by making up their own mind rather than
arbitrarily choosing my interpretation of events over Scott's.
Hamish
On Wed, Jul 2, 2008 at 5:31 PM, Scott Anguish <scott...> wrote:
> Key value Binding and Cocoa Bindings are the same thing.
>
> Key-Value Binding is implemented at the foundation level. Cocoa Bindings is
> the name used for the additional features (controllers, views that support
> bindings, etc..) which is implemented at the AppKit level.
>
> So there is no distinction.
-
Your message is entirely off topic and totally inappropriate.
I can't see how anyone on the list could feel this was an appropriate
response.
On Jul 13, 2008, at 5:06 PM, Hamish Allan wrote:
> <snip private information>
This isn't relevant and is personal information that should not be
posted.. Whether about me, or someone else, this will absolute NOT be
tolerated.
>> I had no idea that it was possible to cause such calamity to a
>> person's reputation simply by disagreeing with them in a public
>> forum;
Continued misrepresentation of ANY list user's position, is
inappropriate. Disagreement is not.
>>
>> let alone to cause them physical distress by doing so. I must
>> therefore apologise for this, and implore anyone reading the thread
>> to
>> allay mmalc's concerns by making up their own mind rather than
>> arbitrarily choosing my interpretation of events over Scott's.
This is harassment, plain and simple.
Behavior such as this is not appropriate for any forum.
This thread is closed.



