| 1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|---|
| 2 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|---|
| 3 | <html xmlns="http://www.w3.org/1999/xhtml">
|
|---|
| 4 | <head>
|
|---|
| 5 | <title>CurrencyConverter HOWTO</title>
|
|---|
| 6 | <link rel="stylesheet" type="text/css" href="../stylesheets/styles.css" />
|
|---|
| 7 | </head>
|
|---|
| 8 |
|
|---|
| 9 | <body>
|
|---|
| 10 |
|
|---|
| 11 | <div class="title">
|
|---|
| 12 | <h1>Writing the Lisp Source</h1>
|
|---|
| 13 | </div>
|
|---|
| 14 |
|
|---|
| 15 | <div class="body-text">
|
|---|
| 16 | <p>In this section we'll write Lisp code that duplicates the
|
|---|
| 17 | features provided by the Objective-C code in Apple's
|
|---|
| 18 | tutorial. In Apple's tutorial, the explanation of the Objective
|
|---|
| 19 | C code begins with the
|
|---|
| 20 | section <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCTutorial/06Controller/chapter_6_section_1.html#//apple_ref/doc/uid/TP40000863-CH8-SW1">Bridging
|
|---|
| 21 | the Model and View: The Controller</a>.</p>
|
|---|
| 22 |
|
|---|
| 23 | <p>The Lisp code in this section of the HOWTO is considerably
|
|---|
| 24 | simpler than the corresponding Objective-C code, in part
|
|---|
| 25 | because we can ignore the conventions that XCode uses for
|
|---|
| 26 | laying out source files. We can just write all our definitions
|
|---|
| 27 | into a single Lisp source file, and load that file into Clozure CL
|
|---|
| 28 | when we are ready to build the application.</p>
|
|---|
| 29 |
|
|---|
| 30 | <div class="section-head">
|
|---|
| 31 | <h2>First Things First</h2>
|
|---|
| 32 | </div>
|
|---|
| 33 |
|
|---|
| 34 | <div class="body-text">
|
|---|
| 35 | <p>Place the following line at the top of your Lisp source file:</p>
|
|---|
| 36 |
|
|---|
| 37 | <pre>(in-package "CCL")</pre>
|
|---|
| 38 |
|
|---|
| 39 | <p>Clozure CL's Objective-C bridge code is defined in the "CCL"
|
|---|
| 40 | package. Usually, when building an application, you'll create a
|
|---|
| 41 | package for that application and import the definitions you need
|
|---|
| 42 | to use. In order to keep the discussion short in this simple
|
|---|
| 43 | example, we just place all our definitions in the "CCL"
|
|---|
| 44 | package.</p>
|
|---|
| 45 |
|
|---|
| 46 | </div>
|
|---|
| 47 |
|
|---|
| 48 | <div class="section-head">
|
|---|
| 49 | <h2>Defining the Converter Class</h2>
|
|---|
| 50 | </div>
|
|---|
| 51 |
|
|---|
| 52 | <div class="body-text">
|
|---|
| 53 | <p>We begin by defining the Converter class. Recall from Apple's
|
|---|
| 54 | tutorial that this is the Model class that implements the
|
|---|
| 55 | conversion between dollars and other currencies. Here is the
|
|---|
| 56 | Lisp definition that implements the class you created in
|
|---|
| 57 | InterfaceBuilder:</p>
|
|---|
| 58 |
|
|---|
| 59 | <pre>
|
|---|
| 60 | (defclass converter (ns:ns-object)
|
|---|
| 61 | ()
|
|---|
| 62 | (:metaclass ns:+ns-object))
|
|---|
| 63 | </pre>
|
|---|
| 64 | </div>
|
|---|
| 65 |
|
|---|
| 66 | <div class="body-text">
|
|---|
| 67 | <p>This is an ordinary CLOS class definition, with a couple of
|
|---|
| 68 | simple wrinkles. First, the superclass it inherits from is the
|
|---|
| 69 | NS-OBJECT class in the "NS" package. NS-OBJECT is an Objective-C
|
|---|
| 70 | class, the ancestor of all Objective-C objects. This CLOS
|
|---|
| 71 | definition actually creates a new Objective-C class named
|
|---|
| 72 | "Converter".</p>
|
|---|
| 73 |
|
|---|
| 74 | <p>We tell Clozure CL how to build the right kind of class object
|
|---|
| 75 | by including the :METACLASS option in the definition:</p>
|
|---|
| 76 |
|
|---|
| 77 | <pre>
|
|---|
| 78 | (:metaclass ns:+ns-object)
|
|---|
| 79 | </pre>
|
|---|
| 80 |
|
|---|
| 81 | <p>The Objective-C bridge knows that when the metaclass
|
|---|
| 82 | is <code>ns:+ns-object</code>, it must lay out the class object
|
|---|
| 83 | in memory as an Objective-C class, rather than a normal CLOS
|
|---|
| 84 | STANDARD-CLASS.</p>
|
|---|
| 85 |
|
|---|
| 86 | <p>Next, we define the method "convertCurrency:atRate:":</p>
|
|---|
| 87 |
|
|---|
| 88 | <pre>
|
|---|
| 89 | (objc:defmethod (#/convertCurrency:atRate: :float)
|
|---|
| 90 | ((self converter) (currency :float) (rate :float))
|
|---|
| 91 | (* currency rate))
|
|---|
| 92 | </pre>
|
|---|
| 93 |
|
|---|
| 94 | <p>This is the method that actually does the currency
|
|---|
| 95 | conversion. It's a Lisp method that will be called when the
|
|---|
| 96 | AppKit sends the Objective-C message "convertCurrency:atRate:"
|
|---|
| 97 | It's very simple—really, it just multiples
|
|---|
| 98 | <code>currency</code> times <code>rate</code>. Most of the text in the definition is
|
|---|
| 99 | Objective-C bridge code that links the definition to the right
|
|---|
| 100 | class with the right argument and return types.</p>
|
|---|
| 101 |
|
|---|
| 102 | <p><code>objc:defmethod</code> is a version of DEFMETHOD that
|
|---|
| 103 | creates methods that can execute in response to Objective-C
|
|---|
| 104 | message-sends.</p>
|
|---|
| 105 |
|
|---|
| 106 | <p>The syntax <code>#/convertCurrency:atRate:</code> uses the
|
|---|
| 107 | "#/" reader macro to read a symbol with case preserved, so that
|
|---|
| 108 | you can see in your code the same name that Objective-C uses for
|
|---|
| 109 | the method, without worrying about how the name might be
|
|---|
| 110 | converted between Lisp and Objective-C conventions.</p>
|
|---|
| 111 |
|
|---|
| 112 | <p>The number of arguments to an Objective-C method is the
|
|---|
| 113 | number of colons in the name, plus one. Each colon indicates an
|
|---|
| 114 | argument, and there is always an extra "self" argument that
|
|---|
| 115 | refers to the object that receives the message. These are normal
|
|---|
| 116 | Objective-C conventions, but we perhaps need to emphasize the
|
|---|
| 117 | details, since we are using Lisp code to call the Objective-C
|
|---|
| 118 | methods.</p>
|
|---|
| 119 |
|
|---|
| 120 | <p>We indicate the return type and the types of arguments in
|
|---|
| 121 | the method definition by surrounding parameters and the method
|
|---|
| 122 | name with parentheses, and appending the type name.</p>
|
|---|
| 123 |
|
|---|
| 124 | <p>Thus, for example, </p>
|
|---|
| 125 |
|
|---|
| 126 | <pre>
|
|---|
| 127 | (#/convertCurrency:atRate: :float)
|
|---|
| 128 | </pre>
|
|---|
| 129 |
|
|---|
| 130 | <p>means that the return type of the method is :FLOAT, and </p>
|
|---|
| 131 |
|
|---|
| 132 | <pre>
|
|---|
| 133 | (self converter)
|
|---|
| 134 | </pre>
|
|---|
| 135 |
|
|---|
| 136 | <p>means that the type of the receiving object is Converter.</p>
|
|---|
| 137 |
|
|---|
| 138 | <p>You will see these same conventions repeated in the next
|
|---|
| 139 | section.</p>
|
|---|
| 140 | </div>
|
|---|
| 141 |
|
|---|
| 142 | <div class="section-head">
|
|---|
| 143 | <h2>Defining the ConverterController Class</h2>
|
|---|
| 144 | </div>
|
|---|
| 145 |
|
|---|
| 146 | <div class="body-text">
|
|---|
| 147 | <p>The previous section defined the Model class, Converter. All
|
|---|
| 148 | we need now is a definition for the ConverterController
|
|---|
| 149 | class. Recall from your reading of Apple's Tutorial that the
|
|---|
| 150 | CurrencyConverter example uses the Model-View-Controller
|
|---|
| 151 | paradigm. You used InterfaceBuilder to construct the
|
|---|
| 152 | application's views. The Converter class provides the model
|
|---|
| 153 | that represents application data. Now we define the controller
|
|---|
| 154 | class, ConverterController, which connects the View and the
|
|---|
| 155 | Model.</p>
|
|---|
| 156 |
|
|---|
| 157 | <p>Here's the definition of the ConverterController class:</p>
|
|---|
| 158 |
|
|---|
| 159 | <pre>
|
|---|
| 160 | (defclass converter-controller (ns:ns-object)
|
|---|
| 161 | ((amount-field :foreign-type :id :accessor amount-field)
|
|---|
| 162 | (converter :foreign-type :id :accessor converter)
|
|---|
| 163 | (dollar-field :foreign-type :id :accessor dollar-field)
|
|---|
| 164 | (rate-field :foreign-type :id :accessor rate-field))
|
|---|
| 165 | (:metaclass ns:+ns-object))
|
|---|
| 166 | </pre>
|
|---|
| 167 |
|
|---|
| 168 | <p>Once again we use the Objective-C bridge to define an
|
|---|
| 169 | Objective-C class. This time, we provide several
|
|---|
| 170 | instance-variable definitions in the class, and name accessors
|
|---|
| 171 | for each of them explicitly. The <code>:FOREIGN-TYPE</code>
|
|---|
| 172 | initargs enable us to specify the type of each field in the
|
|---|
| 173 | foreign (Objective-C) class.</p>
|
|---|
| 174 |
|
|---|
| 175 | <p>Each field in the definition of the ConverterController class
|
|---|
| 176 | is an outlet that will be used to store a reference to one of
|
|---|
| 177 | the text fields that you created in InterfaceBuilder. For
|
|---|
| 178 | example, <code>amount-field</code> will be connected to the
|
|---|
| 179 | "Amount" text field.</p>
|
|---|
| 180 |
|
|---|
| 181 | <p>Why did we spell the name "amount-field" in Lisp code, and
|
|---|
| 182 | "amountField" when creating the outlet in InterfaceBuilder? The
|
|---|
| 183 | Objective-C bridge automatically converts Lisp-style field names
|
|---|
| 184 | (like "amount-field") to Objective-C-style field names (like
|
|---|
| 185 | "amountField"), when handling class definitions.</p>
|
|---|
| 186 |
|
|---|
| 187 | <p>The <code>converter</code> field at launch time contains a
|
|---|
| 188 | reference to the Converter object, whose class definition is in
|
|---|
| 189 | the previous section.</p>
|
|---|
| 190 |
|
|---|
| 191 | <p>The final piece of the implementation is a definition of the
|
|---|
| 192 | "convert:" method. This is the method that is called when a
|
|---|
| 193 | user clicks the "Convert" button in the user interface.</p>
|
|---|
| 194 |
|
|---|
| 195 | <pre>
|
|---|
| 196 | (objc:defmethod #/convert: ((self converter-controller) sender)
|
|---|
| 197 | (let* ((conv (converter self))
|
|---|
| 198 | (dollar-field (dollar-field self))
|
|---|
| 199 | (rate-field (rate-field self))
|
|---|
| 200 | (amount-field (amount-field self))
|
|---|
| 201 | (dollars (#/floatValue dollar-field))
|
|---|
| 202 | (rate (#/floatValue rate-field))
|
|---|
| 203 | (amount (#/convertCurrency:atRate: conv dollars rate)))
|
|---|
| 204 | (#/setFloatValue: amount-field amount)
|
|---|
| 205 | (#/selectText: rate-field self)))
|
|---|
| 206 | </pre>
|
|---|
| 207 |
|
|---|
| 208 | <p>Just as in the Apple example, this method reads the dollar
|
|---|
| 209 | and rate values, and passes them to the
|
|---|
| 210 | "convertCurrency:atRate:" method of the Converter class. It then
|
|---|
| 211 | sets the text of the amount-field to reflect the result of the
|
|---|
| 212 | conversion. The only significant difference between this
|
|---|
| 213 | implementation and Apple's is that the code is written in Lisp
|
|---|
| 214 | rather than Objective-C.</p>
|
|---|
| 215 |
|
|---|
| 216 | <p>This completes the definition of the CurrencyConverter's
|
|---|
| 217 | behavior. All that remains is to actually build the Cocoa
|
|---|
| 218 | application. The next section shows how to do that.</p>
|
|---|
| 219 |
|
|---|
| 220 | </div>
|
|---|
| 221 |
|
|---|
| 222 | <div class="nav">
|
|---|
| 223 | <p><a href="../../HOWTO.html">start</a>|<a href="create_lisp.html">previous</a>|<a href="build_app.html">next</a></p>
|
|---|
| 224 | </div>
|
|---|
| 225 |
|
|---|
| 226 | </body>
|
|---|
| 227 | </html>
|
|---|
| 228 |
|
|---|