Cocoa Programming for Mac OS X - Aaron Hillegass [93]
To solve this problem, the clever engineers at NeXT came up with nil-targeted actions. If you set the target of a control to nil, the application will try to send the action message to several objects until one of them responds. The application first tries to send the message to the first responder of the key window. This is exactly the behavior that you want for Cut and Paste. You can have several windows, each of which can have several views. The active view on the active window gets sent the cut-and-paste messages.
The beauty of targeted actions doesn’t end there. NSView, NSApplication, and NSWindow all inherit from NSResponder, which has an instance variable called nextResponder. If an object doesn’t respond to a nil-targeted action, its nextResponder gets a chance. The nextResponder for a view is usually its superview. The nextResponder of the content view of the window is the window. Thus, the responders are linked together in what we call the responder chain.
Note that nextResponder has nothing to do with nextKeyView.
For example, one menu item closes the key window. It has a target of nil. The action is performClose:. None of the standard objects respond to performClose: except NSWindow. Thus, the selected text field, for example, refuses to respond to performClose:. Then the superview of the text field refuses, and on up the view hierarchy. Ultimately, the window (the key window) accepts the performClose: method. So, to the user, the “active” window is closed.
As was mentioned in Chapter 12, a panel can become the key window but not the main window. If the key window and the main window are different, both windows get a chance to respond to the nil-targeted action.
Your question at this point should be: In what order will the objects be tested before a nil-targeted action is discarded?
1. The firstResponder of the keyWindow and its responder chain. The responder chain would typically include the superviews and, finally, the key window.
2. The delegate of the key window.
3. If it is a document-based application, the NSWindowController and then NSDocument object for the key window.
4. If the main window is different from the key window, it then goes through the same ritual with the main window: the firstResponder of the main window and its responder chain (including the main window itself), the main window’s delegate, and the NSWindowController and then NSDocument object for the main window.
5. The instance of NSApplication.
6. The delegate of the NSApplication.
7. The NSDocumentController.
This series of objects represents the responder chain introduced above. Figure 21.1 presents an example. The numbers indicate the order in which the objects would be asked whether they respond to the nil-targeted action.
Figure 21.1. An Example of the Order in Which Responders Get a Chance to Respond
Note that in document-based applications (such as RaiseMan), the NSDocument object gets a chance to respond to the nil-targeted action. The object receives the messages from the following menu items: Save, Save As..., Revert To Saved, Print..., and Page Layout....
Looking at the XIB File
To continue with our example, open MainMenu.xib. Note that the cut, copy, and paste items are connected to the icon labeled First Responder. The First Responder icon represents nil. It gives you something to drag to when you want an object to have a nil target (Figure 21.2).
Figure 21.2. Check Menu Item
For the More Curious: Which Object Sends the Action Message?
The target on the cut, copy, and paste menu items is nil. We know that sending a message to nil will not do anything. All target-action messages are handled by NSApplication. It has the following method:
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)sender
When the target is nil, NSApplication knows to try to send messages to the objects in the responder chain.
For the More Curious: UTIs and the Pasteboard
In Chapter 10,