Currency Converter (Cocoa)

In this tutorial we are creating a simple currency converter application. We will assemble the user interface in Interface Builder and write the controller and other required classes in Smalltalk. Note that this tutorial is essentially a recreation in Smalltalk of the Currency Converter tutorial provided by the Apple Developer Connection.

Download CurrencyConverter.zip

The application works as follows: the user enters the exchange rate per dollar in the top field, the amount to convert in the middle field, and presses the Convert button. The converted amount displays in the bottom field.

Creating the user interface

In this part we use the Interface Builder to create the nib file containing the Currency Converter main window. There is no programming involved.

  1. Create a new window.

    Open Interface Builder and create a new Cocoa Application. Assign a title and resize the resulting window to match the picture above.

  2. Edit the window.

    Drag controls from the palette and drop them inside the window. You need to use text labels, fields, and one button. Provide a title for the text labels and button to match the picture above. You may also want to attach layout constraints to the controls such that, when the window resizes, the controls resize as well.

  3. Define the Converter and ConverterController classes.

    In Interface Builder, switch to the Classes tab and subclass NSObject with two new classes named Converter and ConverterController. For the controller class, create four outlets named rateField, amountField, resultField, and converter. Also create one action named convert:.

  4. Instantiate Converter and ConverterController classes.

    Select Converter and ConverterController classes one at a time and instantiate them from the popup menu. If you switch to the Instances tab in the Interface Builder you should see the Converter and ConverterController instances.

  5. Edit the outlet and action connections.

    In Interface Builder, connect the ConverterController instance rateField, amountField, and resultField outlets to the rate, amount, and result text field controls inside the main window. Connect the ConverterController instance converter outlet to the Converter instance. Finally, connect the Convert button inside the main window to the ConverterController convert: action.

  6. Save the user interface.

    Save everything to a nib file named CurrencyConverter. Drop this file inside the Smalltalk application package:

    Smalltalk.app/Contents/Resources/English.lproj/CurrencyConverter.nib

Implementing the user interface

In this part we implement the Converter and ConverterController classes inside Smalltalk. Start Smalltalk before you proceed any further.

  1. Implement the Converter class.

    Define the Converter class:

    SmalltalkEnvironment current
       defineClass: #Converter
       type: #fixedSizedReferences
       superclass: ObjectiveCSubObject
       instanceVariableNames: #()
       classInstanceVariableNames: #()
       classVariableNames: #()
       variablePoolNames: #()
       constantPoolNames: #()

    Define an instance method #convertAmount:atRate: to perform basic amount conversion given the rate:

    convertAmount: amount atRate: rate
       ^amount * rate
  2. Implement the ConverterController class.

    Define the ConverterController class. The instance variables for this class represent the outlets defined in the Interface Builder:

    SmalltalkEnvironment current
       defineClass: #ConverterController
       type: #fixedSizedReferences
       superclass: ObjectiveCSubObject
       instanceVariableNames: #(#rateField #amountField #resultField #converter)
       classInstanceVariableNames: #()
       classVariableNames: #()
       variablePoolNames: #()
       constantPoolNames: #()

    Define instance methods to set the outlets. These methods will be exported to Objective-C and have to be named setOutlet: where Outlet is one of the rateField, amountField, resultField, and converter outlet names. The arguments will be Smalltalk ObjectiveCObject instances representing NSTextField and Converter objects:

    setRateField: anObject
       rateField := anObject
    	
    setAmountField: anObject
       amountField := anObject
    
    setResultField: anObject
       resultField := anObject
    
    setConverter: anObject
       converter := anObject

    Define an instance method for the convert: action to compute the converted amount with the help of the converter outlet and store the result in the resultField outlet. This method will be exported to Objective-C and has to be named like the action defined in the Interface Builder. The argument will be a Smalltalk ObjectiveCObject instance representing the sender of the action:

    convert: sender
       resultField setFloatValue: (
          converter 
             convertAmount: amountField floatValue
             atRate: rateField floatValue).
          rateField selectText: self

    Override the superclass method that specifies the Objective-C type encodings. This method returns a literal array of method selectors followed by the Objective-C method signature. All methods listed in this array will be exported to the Objective-C runtime. There are corresponding superclass methods that you can override to export class methods and define the superclass.

    basicObjectiveCInstanceMethodSignatures
       ^#(
          setRateField: #'v@:@'
          setAmountField: #'v@:@'
          setResultField: #'v@:@'
          setConverter: #'v@:@'
          convert: #'v@:@'
          )

Running the application

The only thing left to do is to export the classes to Objective-C and run the application.

  1. Export Converter and ConverterController classes.

    You will need to do this before you start your application for the first time and every time you add/remove/rename outlets and actions in the Interface Builder. Select and evaluate the following:

    Converter updateObjectiveCClass.
    ConverterController updateObjectiveCClass.
  2. Run the application.

    Select and evaluate the following:

    (ObjectiveCObject classNamed: 'NSBundle') 
       loadNibNamed: (ObjectiveCObject string: 'CurrencyConverter') 
       owner: (ObjectiveCObject classNamed: 'NSApplication') sharedApplication