Table Column Bindings
Bindings between the controller and interface are established individually for each interface element. For our application, each table column is considered an element of the interface, so we must establish a binding between the Title table column and the title property of the model by way of the controller we created. We must also create a binding between the Author table column and the author property of
For now, select the Title
NSTableColumn (by whatever combination of clicking and double-clicking that is required to select such a deeply nested control), and open the Bindings inspector for the
NSTableColumn. The Bindings inspector lists all of the attributes of the selected interface element that are available to be bound to an controller. The available bindings include properties such as font attributes and text color, as well as availability states such as whether or not the control is editable, enabled, or hidden. Most importantly for our purposes today, we have a binding for the value of the table column, which is what will be displayed in each row of the table column.
To reveal the options for the value binding, click on the disclosure triangle to the left. This exposes a plethora of options; focus only on the first three options. Here we have three parameters that are used to tell the
NSTableColumn where to get its data from. Bind to is where we specify what controller we will use to obtain the value from the data model. In this popup you should see Book Controller, which is the controller we want to select.
Next we have the parameter Controller Key. Just like any object, instances of
NSArrayController have properties that are accessible via key-value coding. You'll notice that each of the keys in the Controller Key list correspond to methods of
NSArrayController. Here we want to choose arrangedObjects, which corresponds to the
NSArrayController method that returns the
NSArray of data model objects that is managed by the controller; in our case this will be an array of
Finally, we want to specify the Model Key Path, which is simply the key used to access the property of the data model whose value we're interested in displaying. Opening this combo box will reveal all of the keys we specified when we configured Book Controller. For the Title column values, we naturally would like to show the title of the book, so we select the title key for this parameter. With that, we have set up a complete binding between the data model, controller, and a user interface component. Creating the binding for the Author column is exactly the same, except we choose author for the Model Key Path rather than title. When you've configured the binding properly, the inspector should look like the following:
Let's move our attention to the three buttons at the bottom of the main window. Again, the Add button is used to add a new record to the table view, the Remove button will delete the selected record in the table, and the Get Info… button will show a detailed view of the selected record.
NSArrayController defines a number of methods that can be the action of a control. Two of these actions are
add: action will tell the array controller to create a new instance of its data model class, and append it to the array of managed objects. The
remove: action will remove the selected object from the array controller's content array. What we want to do is drag a connection from the Add and Remove buttons to Book Controller and make their actions
NSArrayController also has an action for inserting new items, as well as for changing the current selection to the next or previous object in the array. You could optionally create controls for these actions.
We are ready to test version 1 of our interface. Do this now in Interface Builder by selecting Test Interface from the File menu. The main window will appear, and you should be able to click the Add button to create a new row in the table, and edit the fields of that row. That, dear readers, is how the controller layer works in Cocoa. Pretty slick stuff if you ask me! If you'd like to see some more slick stuff, try entering in several rows of information, and then click on the table column headers. Sorting! Right out of the box without any work on your part!
Let's get back into Interface Builder and set up the bindings for the Inspector, and add a bit of refinement to the way things work.
Setting up the Inspector Bindings
The Get Info… button needs to be able to open up the inspector window. To do this we simply make the action of this button the
makeKeyAndOrderFront: method of the inspector window.
Setting up bindings for the inspector text fields is very similar to what we did for the table columns. Select the title
NSTextField, and open its Bindings inspector. Select the value section to disclose the value bindings options. Just like with the Title table column we select to bind the text field to Book Controller, and the Model Key Path is the title key for the
Book class. The thing that differs is the Controller Key, which we set to selection. This controller key corresponds to the
selection method of
NSObjectController, which for
NSArrayController returns the currently selected object in the content array. By setting the controller key to selection, the text field will always display the title property of the selected table row. Do the same for the Author text field, binding its value to the author property of the model class, and setting the controller key to selection.
When you test run the interface, you will see how the text fields of the inspector track the current selection. Note how the text fields display "No Selection" when there is no selection in the table view. This string is known as a placeholder, and the string that is displayed can be changed in the value binding inspector for the text field. There are four types of placeholders that you can customize: no selection, multiple values, not applicable, and null.
If you've setup the
NSTableView to allow multiple selections, you'll notice that the text fields show the string "Multiple Values" when you have more than one row selected (this is the default multiple values placehold). This is handled intelligently, however. Consider the scenario where we have selected two books in the table: The Odyssey and The Illiad, both by Homer. In the inspector the title field will show "Multiple Values", however, the author field will show "Homer" since all of the selected rows have "Homer" as the author. The emphasis here really is to show when there are multiple values for a single property rather than when there are multiple records selected.
You've probably noticed by now that there are lots of control attributes that we can bind to a controller. One example is in
NSWindow. If you open the Bindings inspector for the inspector window itself, one parameter we can bind to is the window's title. Select title from the list of parameters, and let's bind it to the selection key of Book Controller, and the title model key path. This is exactly what we did to set up the value binding of the title text field. Now the title of the inspector window will match the title of the book that is selected in the main table view. Once again, slick stuff!
Another point of refinement we might like to make is to have the Remove button enabled only when there is a selection made. This is easy to do using the controller bindings technology. In the Bindings inspector for the Remove button open up the parameters for the enabled binding under Availability. Choose to bind to the Book Controller, and under Controller Key select canRemove. This is one of the many keys that correspond to methods in
NSArrayController that return Boolean values, suitable for use as keys to bind to Boolean properties of user-interface controls, such as whether the control is enabled. You could also set up the Add button enabled availability to be bound to the canAdd key of Book Controller.
With the addition of the controller layer, Cocoa goes even further in achieving the core goal of any application framework: eliminate as much repetitive coding as possible so that the developer can focus his energies on developing innovative and polished features that potentially sets his application apart from the rest of the pack. I hope this article has given you a glimpse of what can be done using the controller layer, as well as an idea of how things work in the background so you can explore other bindings options.
You can download the XCode Project for this article here.
Michael Beam is a software engineer in the energy industry specializing in seismic application development on Linux with C++ and Qt. He lives in Houston, Texas with his wife and son.
Return to MacDevCenter.com.