Skip navigation.
 
mlRe: basic bindings question
FROM : Ken Thomases
DATE : Wed May 14 23:11:08 2008

On May 14, 2008, at 2:08 PM, Daniel Child wrote:
> All I'm trying to do is to replace the target-action-outlet 
> approach with bindings in the simplest case I can think of: a text 
> field whose value would correspond to an ivar in the controller. 
> One text field would receive the number, a button would click, pass 
> the number to the ivar, and redisplay that value in another text 
> field.


Actually, requiring the button click to perform the transfer is going 
to make it harder.  It will be easier to just have the field directly 
update the ivar when editing completes.

> First off, is it possible possible to bind directly to an instance 
> variable in the controller? In my hyper-basic example, I'm 
> collapsing M and C. I thought doing so should be OK, so I tried:
>
> Bind to: Controller
> Model Key Path: self.number (number is the ivar) (self presumably 
> being the controller)
>
> This didn't work.


Leave out the "self.".  Just use "number".


> Unfortunately, I am also confused about the intended receiver for 
> addObserver: forKeyPath:. I thought it would be the ivar (number), 
> but I get a warning that NSNumber may not respond to that method 
> (and sure enough the docs show that it doesn't). Logically, the 
> second text field should "observe" that the model/controller ivar 
> (number) has changed. But I thought you were not supposed to use 
> outlets either.


There are two common misconceptions here:

1) KVO is not for observing properties, as such.  It's for observing 
the object which _has_ the property.  To put it another way: I don't 
observe the number, I observe the controller for changes in its 
number property.

2) A property is _not_ the ivar.  The ivar, if it exists at all, is 
an implementation detail of how the class implements the property.  A 
property is part of the interface of the object.  You will find it 
much easier if you conceptualize a property as the set of KVC-
conforming methods in the object's interface.  A "key" is a string 
naming or identifying a property.  (Yes, KVC and KVO provide built-in 
support for properties which don't have accessor methods.  They will 
access the ivar directly.  However, this is just a convenience and a 
fall-back position.  It doesn't materially change how you should 
conceptualize properties.)

To illustrate:

@interface Foo : NSObject
{
   NSNumber* number;    //  <--  This is NOT the property
}

// _These_ are the property:
- (NSNumber*) number;
- (void) setNumber:(NSNumber*)newNumber;

@end


// ... in some other code somewhere

Foo* myFoo = /* ... */
[myFoo addObserver:self forKeyPath:@"number"];

This object (self) is observing the myFoo object for changes in its 
"number" property.


Think also about the KVO notifications you will receive:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)
object change:(NSDictionary *)change context:(void *)context;

Think about what you will be receiving in the "object" parameter of 
that.  You're not interested in knowing that some anonymous, free-
floating NSNumber object has changed; you need to be informed which 
object has had its "number" property changed.  So, in this case, it 
would be the Foo object which was myFoo in the above snippet.  That's 
why you need to conceptualize KVO as observing the object which has 
the property, not as observing the property (or ivar) itself.

Consider the possibility that I use a plain "int" instead of an 
NSNumber as the backing store for the number property of a Foo. 
Surely, the "object" parameter of the observeValueForKeyPath... 
method can't be that int, because an int isn't an object. 
Furthermore, consider if there is _no_ backing storage for the number 
property of a Foo.  What if I changed the above @interface to omit 
the "number" ivar.  Foo still has a "number" property.  Its meaning/
value is whatever results from the semantics of the two methods -
number and -setNumber:.  In theory, they could compute the value on 
the fly, call some library API, or even query a remote server to 
determine the value.  They could do anything and it need not involve 
an ivar of any sort.


Lastly, I want to address a confusion that I've seen at other times 
on this list (but which you didn't express).  Often people have a 
class with an NSMutableArray ivar, and they get confused as to why 
modifications that they make directly to that ivar (as by -
addObject:, for example) don't result in KVO notifications and 
updates to the bound GUI elements.  The reason is that nothing is 
observing that array.  They are observing the owning object for 
changes of the property for which that ivar is backing storage.

The array does not (and can not) send out KVO notifications.  For one 
thing, it doesn't know what object owns it nor what property it 
represents.  The owning object is what sends out the KVO 
notifications.  In order for it to do that, the owning object must be 
messaged.  It might be messaged with a KVC-conforming setter such as 
set<Key>: or insertObject:in<Key>AtIndex:, in which case KVO hooks 
into those methods using low-level techniques of the Objective-C 
runtime (isa-swizzling).  Or, it might be messaged with will/
didChange:valuesAtIndexes:forKey:.  One way or another, though, the 
owning object has to be messaged if it is to produce KVO notifications.

KVO does provide the -mutableArrayValueForKey... methods to create a 
proxy object which you can treat as a mutable array but which 
messages the owning object to carry out the actual modifications.  In 
that way, the owning object is able to send out KVO notifications as 
necessary.  (Even if the proxy ends up accessing the ivar directly, 
it still messages the owning object with -will/
didChange:valuesAtIndexes:forKey:.)


I hope that helps clarify.

Cheers,
Ken

Related mailsAuthorDate
mlbasic bindings question Daniel Child May 14, 21:08
mlRe: basic bindings question Ken Thomases May 14, 23:11
mlRe: basic bindings question Daniel Child May 15, 05:54
mlRe: basic bindings question Ken Thomases May 15, 06:09
mlRe: basic bindings question Daniel Child May 15, 06:43
mlRe: basic bindings question Ken Thomases May 15, 06:54
mlRe: basic bindings question Daniel Child May 16, 04:47
mlRe: basic bindings question Ken Thomases May 16, 05:33