We want the unary minus function (the
button with the “+/-” on it) to
change the sign of the number currently displayed in our
Calculator’s numeric display area. One way to
implement this function is to handle it with another case in the
switch
statement in the enterOp: method — we could give the
“+/-” key its own tag and have the
enterOp: method intercept it and
perform the appropriate function. The problem with this approach is
that the unary minus function has little in common with the other
arithmetic functions: it takes one argument instead of two, and it
operates immediately on the displayed value. A far better way to
implement this function is to implement a new action method in the
Controller class.
Adding new action methods to existing classes is slightly more
difficult than creating the initial class definition. Early versions
of IB simply replaced the existing class files
(Controller.h
and
Controller.m
, here) with new versions, wiping
out any source code that you might have added. Current versions of IB
detect that you have made changes in the class files and allow you to
merge the changes using the Merge Files application. Unfortunately,
this can be a painful and error-prone process. The safest way to add
new outlets and actions to files after they have been created and
edited is to add these items directly to the Objective-C interface
files in a text editor, and then use IB’s
Classes → Read Files
menu command to inform IB about any new actions and outlets.
Back in PB, insert the doUnaryMinus:
action method definition, shown here in
bold, into Controller.h
. (You
can tell that it’s an action method because of its
IBAction typing and because sender
is the only
argument.)
...
- (IBAction)clear:(id)sender;
- (IBAction)clearAll:(id)sender;
- (IBAction)enterDigit:(id)sender;
- (IBAction)enterOp:(id)sender;
- (void)displayX;
- (IBAction)doUnaryMinus:(id)sender;
@end
Now insert the doUnaryMinus: method
shown here into Controller.m
:
- (IBAction)doUnaryMinus:(id)sender
{
X = -X;
[self displayX];
}
Choose PB’s File → Save All menu command to save the Controller class files.
It doesn’t matter where you put this method in
Controller.m
, as long as it’s
between the directives @implementation
and
@end
. However, for consistency, we suggest that
you order the method implementations in the same way that the method
declarations are ordered in the Controller.h
class interface file.
Finally, we have to tell IB about the new doUnaryMinus: method and set up a connection between the on-screen unary minus button and the Controller:
Activate IB by double-clicking MainMenu.nib
in
PB’s main window (MainMenu.nib
is one of the Resources in your project).
Click on the Classes tab in IB’s Nib File window to open the Classes pane.
Select Controller in the class hierarchy in the Classes pane. Because it’s a subclass of NSObject, you may have to scroll to the left (or use the Search field).
Choose IB’s Classes → Read Files menu command.[12]
IB will display the Read Files dialog, as shown in Figure 5-29.
This dialog tells us that the definition for
Controller.h
will be parsed from the edited file
on disk.
Make sure that Controller.h
is selected, as
shown in Figure 5-29, and click Parse in
IB’s Read Files dialog to parse the saved
Controller.h
file on disk.
Make sure that the Controller class is selected in the Nib File window and then type Command-1 to see the Controller’s attributes in the Info dialog.
The new doUnaryMinus: action method should appear in the Controller Info dialog, as in Figure 5-30, indicating that the Read Files command worked.
Double-click the unary minus (“+/-”) button in the Calculator window. Make sure that the NSButton, not the NSMatrix as a whole, is selected.
Connect the selected unary minus button to the Controller instance. Do this by Control-dragging from the button to the Controller instance in the Nib File window (note that the Instances tab view displays automatically) and then double-clicking the doUnaryMinus: action in the NSButtonCell Info dialog.
When a button in an NSMatrix object has its own target, as in the previous example, the button’s target overrides the target of the NSMatrix. Thus, when the user clicks on the unary minus button, the button will send the doUnaryMinus: message to its own target, rather than sending the enterOp: message to the target of the NSMatrix.
Back in PB, build and run the program (note how PB nicely prompts to save files).
The unary minus function should now behave as expected (although the application isn’t perfect yet — it has some bugs).
You might be wondering why IB’s Read Files command
didn’t bring in the definition of the displayX method in addition to the doUnaryMinus: method. The reason is that IB
only looks for action methods when parsing a class interface
(.h
) file. An action
method should always be declared in the form:
- (IBAction)methodname:
(id)sender
;
with a single argument called sender
. As
we’ll see later, IB will also bring in outlet
declarations when parsing a class interface file. These outlet
declarations must be instance variables of the form:
IBOutlet id outletname
;
Action methods and outlets are the only types of information that IB learns about a class when it parses a class interface file.
[12] If you have the Controller class in
IB’s Classes tab selected, you will have an
additional menu item labeled “Read
Controller.h”. As you might imagine, choosing this
menu option causes the Controller.h
file to be
read directly, without forcing you to choose the file in the Read
Files pane. This is a faster method of reading a class
description.
3.14.129.194