Learn Objective-C on the Mac - Mark Dalrymple [66]
Key-Value Observing
The next piece of the puzzle is Key-Value Observing. With KVO, an object can register with another object to be informed of changes as they occur. For instance, continuing with the last example, I can tell myPerson to notify me whenever the value of its firstName attribute changes like this:
In return, myPerson will call a method called observeValueForKeyPath:ofObject:change:context: in the observer whenever the firstName attribute changes, whether that change occurs via the setValue:forKey: method or by someone calling the setFirstName: method. The way this is implemented is quite clever, and involves some meta-programming deep inside Cocoa, creating a subclass of Person at runtime that overrides the setFirstName: method, and passes along a message to all observers after the value changes. This is done so smoothly that you would never suspect the existence of the hidden Person subclass unless you went looking for it, and really dug deep in just the right places. As a result, you don’t really need to know about these implementation details. Just be glad you’re entering into the world of Cocoa programming at a time when this particular technology has matured as much as it has, because it was a little rough around the edges when it first came out!
At the end of the day, you probably won’t need to deal with KVO directly at all. Almost everything you’d ever want to do with KVO can be done more cleanly and easily with Cocoa Bindings, which is built on top of it and provides a higher-level interface. That’s why we’ve focused on the functionality of Cocoa Bindings, and aren’t doing any direct programming with KVO.
Cocoa Bindings: How It Works
While a complete and accurate description of the implementation of Cocoa Bindings is outside the scope of this book, it may be useful for you to get a fuller picture of how it uses KVC and KVO to do its work. Now that you’ve gotten a brief intro into KVC and KVO, let’s take a look at how these bits fit together.
When you establish a binding in Interface Builder, like you’ve done numerous times in this chapter already, you’re actually defining a sort of contract. You’re declaring that when this nib is loaded and these objects are set up, a sequence of events will occur to establish some KVO relationships between the objects, using a key path string (using KVC) to define which attribute is in focus for each binding, along with other information to identify which aspect (e.g. the displayed value, the enabled state, and the like) of the “receiving end” (typically a GUI control) should be affected by changes in the underlying value. At runtime, then, Cocoa will set things up so that the control (or any other object you’ve established a binding on) will be set up to observe changes in the controller based on the relevant key, and the controller will be set up to observe changes in the control’s chosen aspect.
In Conclusion
Bindings are a really powerful technology, and in retrospect you can probably see that’s it’s possible to implement nearly everything shown in Chapters 4 and 5 using Cocoa Bindings, creating an app with almost no custom code whatsoever! This doesn’t in any way diminish the usefulness of the techniques shown in previous chapters, however. The fact is that sometimes you will want to access values in the GUI manually, in methods called by target-action. A general rule of thumb is that if you’re in a situation (a simple app, or a subcomponent of a larger app) where you don’t have any apparent model objects to work with, you may be best served by doing things “the old way,” but, in general, Cocoa Bindings are the preferred method for developing Mac apps from here on out.
In the next few chapters, we’ll show you how to do even more with bindings using