views:

1265

answers:

2

I have trouble understanding Cocoa Bindings. Can someone explain me what this is all about, in an way that is humanly perceivable?

+17  A: 

Bindings is a system for connecting your views to your controllers without writing a lot of glue code to make them explicitly talk to each other. All you have to do is set up properties in both classes* and hook up the binding in IB.

The traditional approach is that the view has one or more outlets to talk to the controller (the most generic examples being delegate and target) and the controller has outlets to talk to the views. When the controller updates the model, it sends (for example) [view modelChange:newModelObject]. When the view wants to update the model, it sends some delegate message to its delegate (the controller), such as NSText's textDidChange:.

With Bindings, all you have to do in code is implement properties on the view and properties on the controller, then expose one or more properties of the view as bindings*. Then you only need to hook up the binding. If it's a Cocoa class, this is cake: just set it up in IB. If it's a custom class of your own, you'll probably write the bind:toObject:withKeyPath:options: message yourself (not much harder).

Let me restate that: With Bindings, your entire glue code (most of the time) is [view bind:@"viewProperty" toObject:self withKeyPath:@"controllerProperty.modelProperty" options:options]; in the controller. Everything else is handled by the Bindings and KVO systems behind the scenes, and by your properties' accessors.

The disadvantage is that you must strictly conform to Cocoa Bindings' requirements. These are simple, but a lot of older applications are designed in a way that doesn't fit Cocoa Bindings.

  • You must create real model objects, not just pass primitive objects (e.g., arrays of dictionaries) around. If you're using Core Data, this is easy: your managed objects are model objects.
  • You must either write your accessors correctly or synthesize the correct accessors. For example, an NSString property should always be @property(copy), never @property(retain) (because otherwise, you will find yourself retaining someone else's mutable string, which they will then mutate while you're holding it).
  • You must only change properties of your model objects by their properties (model.foo = bar) or by accessor messages ([model setFoo:bar]), never by direct instance variable access. (Obvious exception for accessor methods themselves, if you've written your own, because they must access the instance variable directly.)

There are two advantages:

  • You can write a brand new view class without having to rip out a lot of glue code. The most you'll have to delete is some bind:::: messages for the old view's properties. If, a couple of years down the road, you decide that your current view just can't scale to your application's forthcoming capabilities, this gives you the flexibility to rip it out and start afresh with the minimum of pain.
  • More importantly, the less code you have to read, the easier it is to read it.

*And, according to the documentation, implement a KVO observation method in the view class, but I've never actually had to do this. I filed a documentation bug.

Added 2009-03-07: Ah, found a citation. “NSView subclasses can expose additional key-value-coding/key-value-observing compliant properties as bindings by calling the class method exposeBinding: for each of the properties.” —NSKeyValueBindingCreation So you shouldn't need to implement a KVO observation method.

Peter Hosey
I think Peter's got it right. The greatest advantage is eliminating all that "glue code" that updates other parts of your user interface. In even a moderate-size application, that can total thousands of lines of code you don't need to write.
Alex
I think you have to implement the KVO observation protocol in your NSView subclass if you're dealing with properties that are a collection and you want to update on changes to the items *within* the collection.
Barry Wark
Barry Wark: Wouldn't you have to register as an observer for each object, though? Add yourself as they come in, remove yourself as they go out. And that'd be nothing to do with Bindings.
Peter Hosey
@Peter To implement a to-many binding properly, it's almost always necessary to deal with the collection members too. Though, you are right that this is not always the case.
Barry Wark
+9  A: 

Previous answer is very comperhensive and good, I'd just thought I'd add an answer explains what it is at its core without involving Cocoa or Objective-C specifically. That is because the concept itself is language agnostic although dynamic languages like Objective-C makes it a lot easier than more static language like C++.

Example

Say you have two objects M and V. M has methods:

setX(int x);
setY(int y);
int getX();
int getY();

While V has methods:

setA(int x);
setB(int y);
int getA();
int getB();

One way of looking at this is that M has properties x and y and V has properties a and b. You want a change of property x to cause a change in property b and a change in y to cause a change in a.

By change in property x we mean e.g.:

M.setX(10)

where previously

M.getX() != 10

So we want a call of setX on M to cause a call to setA on V.

What bindings allow you to say is that property b on object V is bound to property x on object M. And then this updating is handled automatically. You as a coder don't have to write code that checks if x is changed and then call setB on V. Bindings takes care of this automatically.

Summary

Bindings allows you to bind two properties together that exist on two different objects, so that changing the value of one of the properties causes the dependant property in the other object to change to the same value.

Adam Smith
"So we want a call of setX on M to cause a call to setY on V." should read: "So we want a call of setX on M to cause a call to setA on V." Excellent explanation still.
Dave Gallagher