Cocoa

Glue

OK, by now I think you have everything you need to build a simple application, if you poke about in the APIs a bit to find out the getters and setters to modify a control’s data; for instance, doubleValue and setDoubleValue or title and setTitle. There are better ways, and we’ll get to those, but still: you can make something that really works, rather than just a mock-up UI.

At least, if you stick to buttons and text boxes and sliders and such. It gets fiddlier if you want some of those useful widgets like tables of data, pop-up lists, or even custom controls. They’re easy enough to plonk down in a window, but how to fill them with data?

We need ways of getting data in and out, glue to hook the UI up to the application logic, that goes beyond Outlets and Actions and a whole bunch of method calls.

This will involve covering quite a bit of ground, so we’ll devote several articles to it. But I’m going to give a brief overview here.

Data Sources

Data Sources are the old-fashioned, low-level way of getting data into a Table View or Outline View. They’re not used as much any more, but are still occasionally useful. Essentially, they’re delegates that have methods the widget calls to find out how many items there are, and what the data is for each item. Their primary advantage is that it’s blindingly obvious what’s going on. The disadvantage is the extra code you’re going to write as a result.

Controllers

We saw recently how to make controllers yourself. As well as these, there are several controllers supplied by Cocoa. These have a specific role: They act as middlemen between your data and UI widgets. They can assist with managing selections, sorting list data, and keeping sync when more than one UI widget depends on the same piece of data. This could be because you have multiple ways of viewing/editing something, or you might have an interface where selecting an item in a list causes several other widgets to update (for instance, when you pick a track in iTunes, and the album art changes). Apple call this a “Master-Detail” interface.

Cocoa provides controllers to handle arrays, for list boxes; and to handle tree structures, for outline views. There’s also a specialised controller for dealing with application preferences. These controllers are useful, but rely on several other Cocoa technologies, particularly Cocoa Bindings.

Cocoa Bindings

Chances are, you’ve spent time in the past writing code that handles events and updates values. In “the bad old days”, you might’ve had a function with a giant switch statement in it, checking the type of event, and if it’s (say) a “this checkbox has been clicked” message, you look up the checkbox, get its current ticked/unticked state, and set a bool somewhere to reflect that. Rinse and repeat for every benighted widget in the user-interface. And if those values ever get changed by code, you have to write a bunch of code in the other direction to update the widgets.

Even if you have a decent user-interface framework, and can attach code fairly directly to events (like Borland’s tools, or pre-Bindings Cocoa, or even Visual Basic for all its faults), you still end up writing lots of value = sender.value code.

If you have one of those situations I mentioned before, with multiple widgets dependant on one value, you could be in for a world of pain, with widgets getting out-of-sync, or caught in loops of trying to update each other (Check box: “I changed! I must tell everyone else! You, menu item, you must change!” Menu item: “I changed! I must tell everyone else! You, check box, you must change!” Check box: “I changed! I must tell everyone else…”). Yes, yes, you can avoid all these bugs, but it’s still miserable, thankless work.

Fortunately, Cocoa Bindings does all that for you. You tell Interface Builder which instance variable should be linked to a widget’s value. You can link multiple widgets to the same variable. You can link variables to a variety of attributes, not just the value (eg enabled/disabled, shown/hidden, label, colour…). This is fantastic.

How it works, in turn, depends on two other technologies: KVC and KVO. These will be the subject of our next article in this series.