< Previous PageNext Page >

The Target-Action Mechanism

While delegation, bindings, and notification are useful for handling certain forms of communication between objects in a program, they are not particularly suitable for the most visible sort of communication. A typical application's user interface consists of a number of graphical objects, and perhaps the most common of these objects are controls. A control is a graphical analogue of a real-world or logical device (button, slider, check boxes, and so on); as with a real-word control, such as a radio tuner, you use it to convey your intent to some system of which it is a part—in our case, an application.

The role of a control on a user interface is simple: It interprets the intent of the user and instructs some other object to carry out that request. When a user acts on the control by, say, clicking it or pressing the Return key, the hardware device generates a raw event. The control accepts the event (as appropriately packaged for Cocoa) and translates it into an instruction that is specific to the application. However, events by themselves don't give much information about the user's intent; they merely tell you that the user clicked a mouse button or pressed a key. So some mechanism must be called upon to provide the translation between event and instruction. This mechanism is called target-action.

Cocoa uses the target-action mechanism for communication between a control and another object. This mechanism allows the control and its cell (or cells) to encapsulate the information necessary to send an application-specific instruction to the appropriate object. The receiving object—typically an instance of a custom class—is called the target. The action is the message that the control sends to the target. The object that is interested in the user event—the target—is the one that imparts significance to it, and this significance is usually reflected in the name it gives to the action.

In this section:

Controls, Cells, and Menu Items
The Target
The Action
Actions Defined by the Application Kit
Setting the Target and Action


Controls, Cells, and Menu Items

Most controls are objects that inherit from the NSControl class. Although a control has the initial responsibility for sending an action message to its target, it rarely carries the information needed to send the message. For this, it usually relies on its cell or cells.

A control almost always has one or more cells—objects that inherit from NSCell—associated with it. Why is there this association? A control is a relatively “heavy” object because it inherits all the combined instance variables of its ancestors, which include the NSView and NSResponder classes. Because controls are expensive, cells are used to subdivide the screen real estate of a control into various functional areas. Cells are lightweight objects that can be thought of as overlaying all or part of the control. But it's not only a division of area, it's a division of labor. Cells do some of the drawing that controls would otherwise have to do, and cells hold some of the data that controls would otherwise have to carry. Two items of this data are the instance variables for target and action. Figure 5-4 depicts the control-cell mechanism.

Being abstract classes, NSControl and NSCell both incompletely handle the setting of the target and action instance variables. By default, NSControl simply sets the information in its associated cell, if one exists. (NSControl itself supports only a one-to-one mapping between itself and a cell; subclasses of NSControl such as NSMatrix support multiple cells.) In its default implementation, NSCell simply raises an exception. You must go one step further down the inheritance chain to find the class that really implements the setting of target and action: NSActionCell.

Objects derived from NSActionCell provide target and action values to their controls so the controls can compose and send an action message to the proper receiver. An NSActionCell object handles mouse (cursor) tracking by highlighting its area and assisting its control in sending action messages to the specified target. In most cases, the responsibility for an NSControl object’s appearance and behavior is completely given over to a corresponding NSActionCell object. (NSMatrix, and its subclass NSForm, are subclasses of NSControl that don’t follow this rule.)


Figure 5-4  How the target–action mechanism works

How the target–action mechanism works

When users choose an item from a menu, an action is sent to a target. Yet menus (NSMenu objects) and their items (NSMenuItem objects) are completely separate, in an architectural sense, from controls and cells. The NSMenuItem class implements the target–action mechanism for its own instances; an NSMenuItem object has both target and action instance variables (and related accessor methods) and sends the action message to the target when a user chooses it.

Note: “Controls and Menus” discusses control-cell and menu architecture in greater detail. Also see Control and Cell Programming Topics for Cocoa and Application Menu and Pop-up List Programming Topics for Cocoa.

The Target

A target is a receiver of an action message. A control or, more frequently, its cell holds the target of its action message as an outlet (see “Outlets”). The target usually is an instance of one of your custom classes, although it can be any Cocoa object whose class implements the appropriate action method.

You can also set a cell's or control's target outlet to nil and let the target object be determined at run time. When the target is nil, the NSApplication object searches for an appropriate receiver in a prescribed order:

  1. It begins with the first responder in the key window and follows nextResponder links up the responder chain to the NSWindow object’s content view.

    Note: A key window responds to key presses for an application and is the receiver of messages from menus and dialogs. An application’s main window is the principal focus of user actions and often has key status as well.

  2. It tries the NSWindow object and then the window object’s delegate.

  3. If the main window is different from the key window, it then starts over with the first responder in the main window and works its way up the main window’s responder chain to the NSWindow object and its delegate.

  4. Next, the NSApplication object tries to respond itself. If it can’t respond, it tries its own delegate. NSApp and its delegate are the receivers of last resort.

Control objects do not (and should not) retain their targets. However, clients of controls sending action messages (applications, usually) are responsible for ensuring that their targets are around to receive action messages. To do this, they may have to retain their targets. This precaution applies equally to delegates and data sources.

The Action

An action is the message a control sends to the target or, from the perspective of the target, the method it implements to respond to the action. A control or, more frequently, its cell stores an action as an instance variable of type SEL. SEL is an Objective-C data type used to specify the signature of a message. An action message must have a simple, distinct signature. The method it invokes returns nothing and has a sole argument of type id. This argument, by convention, is named sender. Here is an example from the NSResponder class, which defines a number of action methods:

- (void)capitalizeWord:(id)sender;

Action methods can also have the following signature, which is equivalent:

- (IBAction) deleteRecord:(id)sender;

In this case, IBAction does not designate a data type for a return value; no value is returned. IBAction is a type qualifier that Interface Builder notices during application development to synchronize actions added programmatically with its internal list of action methods defined for a project.

The sender parameter usually identifies the control sending the action message (although it can be another object substituted by the actual sender). The idea behind this is similar to a return address on a postcard. The target can query the sender for more information if it needs to. If the actual sending object substitutes another object as sender, you should treat that object in the same way. For example, say you have a text field and when the user enters text, the (arbitrarily named) action method nameEntered: is invoked in the target:

- (void)nameEntered:(id) sender {
    NSString *name = [sender stringValue];
    if (![name isEqualToString:@""]) {
        NSMutableArray *names = [self nameList];
        [names addObject:name];
        [sender setStringValue:@""];
    }
}

Here the responding method extracts the contents of the text field, adds the string to an array cached as an instance variable, and clears the field. Other possible queries to sender would be asking an NSMatrix object for its selected row ([sender selectedRow]), asking an NSButton object for its state ([sender state]), and asking any cell associated with a control for its tag ([[sender cell] tag]), a tag being an arbitrary identifier.

Actions Defined by the Application Kit

The Application Kit not only includes many NSActionCell-using controls for sending action messages, it defines action methods in many of its classes. Some of these actions are connected to default targets when you create a Cocoa application project. For example, the Quit command in the application menu is connected to the terminate: method in the global application object (NSApp).

The NSResponder class also defines many default action messages (also known as standard commands) for common operations on text. This allows the Cocoa text system to send these action messages up an application's responder chain—a hierarchical sequence of event-handling objects—where it can be handled by the first NSView, NSWindow, or NSApplication object that implements the corresponding method.

Setting the Target and Action

You can set the targets and actions of cells and controls programmatically or by using Interface Builder. For most developers and most situations, Interface Builder is the preferred approach. When you use it to set controls and targets, Interface Builder provides visual confirmation, allows you to lock the connections, and archives the connections to a nib file. The procedure, which is covered in more detail in the development-tools documentation, is simple:

  1. Define an action method in your custom class.

  2. Make an instance of your custom class (if it doesn't already exist).

  3. Control–drag a connection line from the control or cell object to the icon representing the instance of your custom class.

  4. In the Connections pane of the inspector (which Interface Builder automatically displays), select the action method and click Connect.


Figure 5-5  Setting target and action in Interface Builder

Setting target and action in Interface Builder

If the action is handled by a superclass of your custom class or by an off-the-shelf Application Kit class, you can skip the first step. Of course, if you define the action method yourself, you must be sure to implement it.

To set the action and the target programmatically, use the following methods to send messages to a control or cell object:

- (void)setTarget:(id)anObject;
- (void)setAction:(SEL)aSelector;

The following example shows how you might use these methods:

[aCell setTarget:myController];
[aControl setAction:@selector(deleteRecord:)];
[aMenuItem setAction:@selector(showGuides:)];

Programmatically setting the target and action does have its advantages and indeed in certain situations it is the only possible approach. For example, you might want the target or action to vary according to some runtime condition, such as whether a network connection exists or whether an inspector window has been loaded. Another example is when you are dynamically populating the items of a pop-up menu, and you want each pop-up item to have its own action.



< 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.