< Previous PageNext Page >

Delegates and Data Sources

A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program. The delegating object is usually a responder object—that is, an object inheriting from NSResponder—that is responding to a user event. The delegate is an object that is delegated control of the user interface for that event, or is at least asked to interpret the event in an application-specific manner.

To better appreciate the value of delegation, it helps to consider an off-the-shelf Cocoa object such as a window (an instance of NSWindow) or a table view (an instance of NSTableView). These objects are designed to fulfill a specific role in a generic fashion; a window object, for example, responds to mouse manipulations of its controls and handles such things as closing, resizing, and moving the physical window. This restricted and generic behavior necessarily limits what the object can know about how an event affects (or will affect) something elsewhere in the application, especially when the affected behavior is specific to your application. Delegation provides a way for your custom object to communicate application-specific behavior to the off-the-shelf object.

The programming mechanism of delegation gives objects a chance to coordinate their appearance and state with changes occurring elsewhere in a program, changes usually brought about by user actions. More importantly, delegation makes it possible for one object to alter the behavior of another object without the need to inherit from it. The delegate is almost always one of your custom objects, and by definition it incorporates application-specific logic that the generic and delegating object cannot possibly know itself.

In this section:

How Delegation Works
The Form of Delegation Messages
Delegation and the Application Kit
Data Sources
Implementing a Delegate for a Custom Class


How Delegation Works

The design of the delegation mechanism is simple (Figure 5-2). The delegating class has an outlet, usually one that is named delegate, and includes methods for setting and accessing this outlet. It also declares, without implementing, one or more methods that constitute an informal protocol. An informal protocol, which typically occurs as a category of the delegating class, differs from a formal protocol in that the delegate does not have to implement all of the methods in the protocol. The delegate implements only those methods of the informal protocol where it has an interest in coordinating itself with the delegating object or affecting that object’s default behavior.


Figure 5-2  The mechanism of delegation

The mechanism of delegation

The methods of the informal protocol mark significant events handled or anticipated by the delegating object. This object wants either to communicate these events to the delegate or, for impending events, to request input or approval from the delegate. For example, when a user clicks the close button of a window, the window object sends the windowShouldClose: message to its delegate; this gives the delegate the opportunity to veto or defer the closing of the window if, for example, the window has associated data that must be saved (see Figure 5-3).


Figure 5-3  A more realistic sequence involving a delegate

A more realistic sequence involving a delegate

The delegating object sends a message only if the delegate implements the method. It makes this discovery by invoking the NSObject method respondsToSelector: in the delegate first. This prior check is key to the design of informal protocols.

The Form of Delegation Messages

Delegation methods have a conventional form. They begin with the name of the Application Kit object doing the delegating—application, window, control, and so on; this name is in lower-case and without the “NS” prefix. Usually (but not always) this object name is followed by an auxiliary verb indicative of the temporal status of the reported event. This verb, in other words, indicates whether the event is about to occur (“Should” or “Will”) or whether it has just occurred (“Did” or “Has”). This temporal distinction helps to categorize those messages that expect a return value and those that don’t. Listing 5-1 includes a few Application Kit delegation methods that expect a return value.

Listing 5-1  Sample delegation methods with return values

- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
- (BOOL)textShouldBeginEditing:(NSText *)textObject;
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame;

The delegate that implements these methods can block the impending event (by returning NO in the first two), defer the impending event (by returning NSTerminateLater in the applicationShouldTerminate: method), or alter a suggested parameter (the frame rectangle in the last method).

The other sort of delegation methods are invoked by messages that don’t expect a return value and so are typed to return void. These messages are purely informational, and the method names often contain “Did” or some other indication of a transpired event. Listing 5-2 shows a few examples of this kind of delegation method.

Listing 5-2  Sample delegation methods returning void

- (void) tableView:(NSTableView*)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn;
- (void)applicationDidUnhide:(NSNotification *)notification;
- (void)applicationWillBecomeActive:(NSNotification *)notification;
- (void)windowDidMove:(NSNotification *)notification;

There are couple of things to note about this last group of messages. The first is that an auxiliary verb of “Will” (as in the third method) does not necessarily mean that a return value is expected. In this case, the event is imminent and cannot be blocked, but the message gives the delegate an opportunity to prepare the program for the event.

The other point of interest concerns the last three of the methods. The sole parameter of each of these methods is an NSNotification object, which means that they are invoked as the result of the posting of a particular notification. For example, the windowDidMove: method is associated with the NSWindow method NSWindowDidMoveNotification. The section “Notifications” discusses notifications in detail, but here it’s important to understand the relation of notifications to delegation messages. The delegating object automatically makes its delegate an observer of all notifications it posts. All the delegate needs to do is implement the associated method to get the notification.

To make an instance of your custom class the delegate of an Application Kit object, simply connect the instance to the delegate outlet in Interface Builder. Or you can set it programmatically through the delegating object’s setDelegate: method, preferably early on, such as in the awakeFromNib method.

Delegation and the Application Kit

The delegating object in an application is often an NSApplication, NSWindow, or NSView object. The delegate object itself is typically, but not necessarily, an object, often a custom object, that controls some part of the application (that is, a coordinating controller object). Table 5-1 lists the Application Kit classes that define a delegate.

Table 5-1  Application Kit classes with delegates

NSApplication

NSFontManager

NSSplitView

NSTextField

NSBrowser

NSFontPanel

NSTableView

NSTextView

NSControl

NSMatrix

NSTabView

NSWindow

NSDrawer

NSOutlineView

NSText

Delegating objects do not (and should not) retain their delegates. However, clients of delegating objects (applications, usually) are responsible for ensuring that their delegates are around to receive delegation messages. To do this, they may have to retain the delegate. This precaution applies equally to data sources, notification observers, and targets of action messages.

Some Application Kit classes have a more restricted type of delegate called a modal delegate. Objects of these classes (NSOpenPanel, for example) run modal dialogs that invoke a handler method in the designated delegate when the user clicks the dialog’s OK button. Modal delegates are limited in scope to the operation of the modal dialog.

The existence of delegates has other programmatic uses. For example, with delegates it is easy for two coordinating controllers in the same program to find and communicate with each other. For example, the object controlling the application overall can find the controller of the application’s inspector window (assuming it’s the current key window) using code similar to the following:

id winController = [[NSApp keyWindow] delegate];

And your code can find the application-controller object—by definition, the delegate of the global application instance—by doing something similar to the following:

id appController = [NSApp delegate];

Data Sources

A data source is like a delegate except that, instead of being delegated control of the user interface, it is delegated control of data. A data source is an outlet held by NSView objects such as table views and outline views that require a source from which to populate their rows of visible data. The data source for a view is usually the same object that acts as its delegate, but it can be any object. As with the delegate, the data source must implement one or more methods of an informal protocol to supply the view with the data it needs and, in more advanced implementations, to handle data that users directly edit in such views.

As with delegates, data sources are objects that must be present to receive messages from the objects requesting data. The application that uses them must ensure their persistence, retaining them if necessary.

Data sources are responsible for the persistence of the objects they hand out to user-interface objects. In other words, they are responsible for the memory management of those objects. However, whenever a view object such as an outline view or table view accesses the data from a data source, it retains the objects as long as it uses the data. But it does not use the data very long. Typically it only holds on to the data long enough to display it.

Implementing a Delegate for a Custom Class

To implement a delegate for your custom class, complete the following steps:



< Previous PageNext Page >


© 2006 Apple Computer, Inc. All Rights Reserved. (Last updated: 2006-12-20)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.