Enhanced Currency Converter
George Wright
gwright@labyrinth.net.au
Currency Converter Enhanced
Introduction
In an earlier article 'Currency Converter Revisited' (AUSOM NEWS May 2004) you used Cocoa bindings and an instance of NSController to establish links between data displayed in three text fields in the application window. Cocoa documentation provides a tutorial called "Currency Converter Enhanced" which builds a master-detail version of the application. It shows how to use an NSArrayController to control many instances of the converter in a column view. The approach is to begin with the completed "Currency Converter With Bindings" and modify the user interface and code to create an enhanced version of the application. Here I have chosen to start from scratch again rather than modify an existing project. I hope this approach is helpful. I suggest you do the previous tutorial first and have the original document "ccwithbindingsplus.html" available too. A reminder that you will need to have installed the Xcode Tools disk. For the record, I am running Xcode 1.0 and Mac OS X 10.3.3.
Create a New Project
The early part of this tutorial should be familiar.
1. Choose New Project from the File menu.
2. Select Cocoa Document-based Application in Xcodes project Assistant window, and click the Next button.
3. Enter the project name (for example, enter NewCurrencyConverterEnhanced) and a destination folder for the project.
4. Open MyDocument.nib in Interface Builder by double-clicking its icon which shows up when you click the NIB Files disclosure triangle.
Build the User Interface
5. In Interface Builder remove default text from the window then drag three text fields and three labels from the Text palette.
6. Change the three labels to Exchange Rate, Dollars to Convert, and Amount in Other Currency.
7. Arrange the objects and change their labels. Add number formatters to each field to achieve the formats shown below.
8. Increase the height of MyDocuments window, if necessary, and from the Cocoa Data panel, drag an NSTableView into the lower half of the window.

Details of the selected row populate the text fields
9. Use the setting in the Attributes panel to add a third column to the table view. Label the columns, from left to right: Exchange Rate, Dollars to Convert, Amount in Other Currency.
10. Add number formatters to each column. First select the column heading then drag a formatter from the Text palette to the column header. Use the same formatters you chose for the text fields.
11. Drag two buttons from the Controls palette to MyDocuments window. Label one Add Row and the other Remove Row. Compare your user interface with that shown in the picture.
Create the Models
12. To create a subclass of NSObject click the Classes tab in the MyDocument.nib window. Select NSObject and hit Return.
13. Change the name of the new subclass to Converter.
14. While the Converter class is selected in the MyDocument.nib window, choose Create Files for Converter from the Classes menu. Save IB.
15. Back in Xcode add the following declarations - for instance variables dollarsToConvert and exchangeRate and the method amountInOtherCurrency, to Converter.h. The lines to add are shown in bold.
/* Converter */
#import <Cocoa/Cocoa.h>
@interface Converter : NSObject
{
double dollarsToConvert;
double exchangeRate;
}
- (double)amountInOtherCurrency;
@end
16. Add the following method implementation to Converter.m.
#import "Converter.h"
@implementation Converter
- (double)amountInOtherCurrency {
return (double)(dollarsToConvert * exchangeRate);
}
@end
Cocoa Bindings provides a class method you can use to trigger a change notification to update a dependent key. You can set up a dependency between changing the values of the dollarsToConvert and exchangeRate keys to trigger an update of the value of the amountInOtherCurrency key. You typically set up this dependency in the initialize class method belonging to the model class:
17. Implement Converters +initialize method in Converter.m:
#import "Converter.h"
@implementation Converter
+ (void)initialize {
[Converter setKeys:
[NSArray arrayWithObjects:@"dollarsToConvert", @"exchangeRate", nil]
triggerChangeNotificationsForDependentKey:@"amountInOtherCurrency"];
}
- (double)amountInOtherCurrency {
return (double)(dollarsToConvert * exchangeRate);
}
@end
Now add your model, an instance of Converter, to the nib file:
18. Click the classes tab in the MyDocument.nib window in Interface Builder.
19. Select Converter and choose Instantiate Converter from the Classes menu.
Add a Controller - Instantiate an NSArrayController
The NewCurrencyConverterEnhanced application in this section manages an array of model objects, so NSArrayController is the appropriate choice - rather than NSObjectController as in the previous tutorial. You add an array controller as follows:
20. Drag NSArrayController from the Controller palette to the nib file window.
21. Rename the controller as "ConversionFormulas". Save in OSX 10.2 format.
Object Class Name
In the Attributes pane of the ConversionFormulas the two attributes you need be concerned with are the object class name and the controllers keys. The object class name specifies the model object the controller manages. When you add an object to the array controller, it creates an instance of the class specified by its object class name by default, NSMutableDictionary. But in this application you want the array controller to manage a collection of model objects. So, you need to tell the array controller to use your Converter model class instead. In order for the array controller to manage a collection of Converter objects, you need to specify that class as the controllers object class name.

The Object Class Name is Converter
You also need to tell the controller what model keys to expose to its views. Add the keys: dollarsToConvert, exchangeRate, and amountInOtherCurrency.
Follow these steps to configure the array controller:
22. With the array controller selected in the nib file window, display the Attributes pane in the Info window.
23. Enter Converter in the Object Class Name text field.
24. Using the Add button, add these model keys: dollarsToConvert, exchangeRate, and amountInOtherCurrency. These are the same keys entered in the +initialize method above.
Establish the Model-Controller Relationship
You can connect the controller to the model object, the instance of Converter you created above, as follows:
25. Control-drag a connection from the array controller (ConversionFormulas) to the Converter object in the MyDocument.nib window.
26. Connect the controllers only outlet, content

Connecting the Array Controller to the Model
Associate Controller With View Objects
Now that you have connected the controller and the model, and exposed the desired model keys, you can start binding user interface elements to the controller.

For binding text fields the Controller Key is selection
Follow these steps to bind each of the three text fields:
27. Select the text field, display the Bindings pane in the Info window (Command + 4), and disclose the value binding.
28. In the Bind to drop down menu, choose ConversionFormulas - which is the array controller .
29. Choose selection from the Controller Key menu - it should come up automatically. The selection referred to here is the row of the table to be selected - one of the objects controlled by ConversionFormulas.
30. Depending on the text field selected, choose the appropriate model key from the Model Key Path menu.
Creating a Master-Detail Interface
Although you can edit conversions in the table view, it is more convenient to do so in the detail text fields above the table view. This style of user interface is called a master-detail interface where the interface that manages the collection is called the master, and the one managing the selected object in the collection is called the detail interface. This is an example of Cocoa Bindings managing multiple views since the property values of the selected object will appear both in the table cells in the lower part of the window and the text fields in the upper part. Cocoa Bindings makes it easy to associate the selected row in a table with other user-interface objects. These bindings form relationships between the values of the text fields and the currently selected row in the table. The 'selection' controller key tells the controller to use the currently selected object in the table view as the object to which that row is bound. It identifies a single item in the array controller whereas the arrangedObjects key identifies all the objects in the array controller. Now that youve configured an array controller to manage a collection of the model objects, youre ready to hook it up to the user interface. The array controller youve already configured will be the tables data source. To form this relationship, you bind each of the tables columns to a different model key in the array controller.

For binding columns the Controller Key is arrangedObjects
Configure the bindings for each of the three columns in the table as follows:
31. Select the table column by repeatedly double-clicking on the table column header and display the Bindings pane in the Info window.
32. Reveal the columns value binding and choose ConversionFormulas from the Bind to menu.
33. Choose arrangedObjects from the Controller Key menu.
34. Choose the corresponding model key from the Model Key Path menu.
With this bindings setup the value of each cell in the Dollars to Convert column is bound to the dollarsToConvert key in the model object that is managed by the ConversionFormulas controller. The arrangedObjects controller key specifies that the data source of the column is the array of objects managed by the ConversionFormulas controller. In other words, each column uses the data set provided by the controllers arrangedObjects key, and uses the model key to display a particular property of the object in the column.
Add New Model Objects to The Controller
Youve now identified where the values of the model objects are displayed, but you still need a way to add model objects to the array controller.This is the purpose of the buttons. Follow these steps to connect the Add Row and Remove Row buttons to the controller:
35. Control-drag from the Add Row button to ConversionFormulas in the Instances Tab of MyDocument.nib. The Connections pane should appear in the Info window with the Target/Actions tab selected.
36. Select the add: action, and click Connect. ConversionFormulas is an array controller object with a built in response to the add: message.
37. Similarly, connect the Remove Row button to the array controllers remove: action.
Build and Run
38. Build and run the application.
Users enter data in the Dollars to Convert and Exchange Rate text fields, and when they finish editing either of those fields, the views send messages to controller that cause Cocoa Bindings to attempt to set the value of the dollarsToConvert and exchangeRate instance variables and also to get the value of the amountInOtherCurrency method. A dependency was established between these model keys in the initialize method. You can also edit exchangeRate and dollarsToConvert fields by double clicking a cell in in the table columns. I did however find some strange behaviour results if you edit the third column or the third field. You can add new conversions by clicking the Add Row button. Behind the scenes, clicking the Add Row button creates a new Converter instance and adds it to the table. Remember, the array controller was configured to manage Converter objects. After you have several rows in the table click a column header to sort the whole table ascending or descending by that column.
Acknowledgements
I have relied on the document "ccwithbindingsplus.html" downloaded from the Apple Developer site and "ControllerLayer" documentation installed from the Xcode disk. I have also referred to other tutorials and articles on bindings in the CocoaBindings/Concepts/ folder of the documentation. By the way, the simpler tutorial ccwithbindings.html failed to work for me until I added the +initialise code as above (with the receiver Converter replaced by self). I would be pleased to hear from beginning Cocoa programmers who have worked through this article, and also from those who have chosen not to work through it. This tutorial and others I have published in Ausom News can be found on http://www.labyrinth.net.au~/gwright