DKStyle and Key-Value Observing (KVO)¶
The immense variety and sheer number of properties embodied within a DKStyle and all its component rasterizers make managing them for Undo and notifying their clients quite a task. Luckily, Cocoa has a mechanism called Key-Value Observing (KVO) that considerably eases the amount of work we need to do. DKStyle uses KVO to “observe” all of the interesting properties of all of its component rasterizers. This allows it to centralise all of the Undo processing and also updating all of its clients when any property of any component is changed. The beauty of this approach is that the rasterizers themselves need to do very little work to take advantage of this - in fact each class just has to publish a simple list of strings which are the names of the KVC-compliant properties that it wants to be undoable. It can do this because DKRasterizer subclasses GCObservableObject, which simplifies much of the work needed to observe properties using KVO.
Each rasterizer class has the method + observableKeyPaths which returns an array of strings, each being an undoable property of instances of the class. Subclasses can call super and add their own properties, so a list of all properties for any given class can be built up. When a rasterizer is added to a style, the style uses this list to set itself as an observer for all of the listed properties. When the style is released or a rasterizer removed, the style removes itself as an observer in the same way. As an observer, the style “sees” any changes to any of the published properties.
To make handling Undo even more user-friendly, each rasterizer class should implement the -registerActionNames: method, and register an action name for each property. DKStyle will use these action names when setting up the Undo menu item for the observed property.
- As anyone who has worked with KVO will know, getting it right can sometimes be tricky.
- This might matter if you subclass DKRasterizer. In most cases you can implement +observableKeyPaths and -registerActionNames and be done, but if any sub-properties within the rasterizer are themselves observable, you need to also override -setUpKVOForObserver: and -tearDownKVOForObserver: (inherited from GCObservableObject) and set up observation for the properties of the additional sub-property object. (An example of this in DK is DKGradient, which is a property of DKFill but does itself have observable properties of its own). If your sub-property objects subclass GCObservableObject, you can extend the simplified KVO approach of publishing your observable key paths to such objects quite easily.