I have trouble understanding Cocoa Bindings. Can someone explain me what this is all about, in an way that is humanly perceivable?
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.
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.