source: trunk/source/examples/cocoa/nib-loading/HOWTO.html @ 8479

Last change on this file since 8479 was 8479, checked in by mikel, 12 years ago

edits to the nob-loading HOWTO

File size: 11.1 KB
Line 
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>Nib-Loading HOWTO</title>
6    <link rel="stylesheet" type="text/css" href="HOWTO_files/stylesheets/styles.css" />
7  </head>
8
9  <body>
10
11    <div class="title">
12      <h1>Nib-Loading HOWTO</h1>
13    </div>
14
15    <div class="body-text">
16      <p>This HOWTO shows how you can load <strong>nibfiles</strong>
17        into a running copy of Clozure CL by evaluating Lisp forms. You
18        might want to load nibfiles this way to test user-interface
19        elements that you are working on for an application project, or
20        to enable an application to dynamically load optional
21        user-interface elements.</p>
22
23    </div>
24
25    <div class="section-head">
26      <h2>Nibfiles</h2>
27    </div>
28
29    <div class="body-text">
30      <p>A large part of developing Cocoa applications is creating
31        user-interface elements using the Cocoa frameworks. Although
32        it's perfectly possible to create any user-interface element
33        just by making method calls against the frameworks, the more
34        standard way to design a user interface is to use Apple's
35        InterfaceBuilder application to
36        create <strong>nibfiles</strong>&mdash;files of archived
37        Objective-C objects that implement the user-interface
38        elements.</p>
39     
40      <p>InterfaceBuilder is an application that ships with Apple's
41        Developer Tools. The Developer Tools are an optional install
42        that comes with Mac OS X. Before you can use this HOWTO, you'll
43        need to make sure that Apple's Developer Tools are installed on
44        your system. Members of Apple's developer programs may download
45        the tools for free from
46        Apple's <href="http://developer.apple.com">developer
47          website</href>, but normally there is no need. You can simply
48        use the optional Developer Tools installer on the Mac OS X
49        system disks to install the tools.</p>
50    </div>
51
52    <div class="section-head">
53      <h2>Using Nibfiles</h2> 
54    </div>
55
56    <div class="body-text">
57      <p>Using InterfaceBuilder, you can quickly and easily create
58        windows, dialog boxes, text fields, buttons, and other
59        user-interface elements. The elements you create with
60        InterfaceBuilder have the standard appearance and behavior
61        specified by Apple's Human Interface Guidelines.</p>
62
63      <p>InterfaceBuilder saves descriptions of these objects
64        in <strong>nibfiles</strong>. These files contain archived
65        representations of Objective-C classes and objects. When you
66        launch an application and it loads a nibfile, the Cocoa runtime
67        creates these Objective-C objects in memory, complete with any
68        instance-variable references to other objects that might have
69        been saved in the nibfile. In short, a nibfile is an archived
70        collection of user-interface objects that Cocoa can quickly and
71        easily revive in memory.</p>
72
73      <p>The normal way that Objective-C programmers use nibfiles is
74        by storing them in an application bundle. The application's
75        Info.plist file (also stored in the bundle) specifies which
76        nibfile is the application's main nibfile, and that file is
77        loaded automatically when the application starts up. The
78        application can dynamically load other nibfiles from the bundle
79        by making method calls.</p>
80
81      <p>Lisp applications written with Clozure CL can also use
82        nibfiles in this same fashion (see the "currency-converter"
83        HOWTO in the "cocoa" examples folder), but Lisp programmers are
84        accustomed to highly interactive development, and might want to
85        simply load an arbitrary nibfile into a running Clozure CL
86        session. Fortunately, this is easy to do.</p>
87    </div>
88
89    <div class="section-head">
90      <h2>How To Load a Nibfile</h2> 
91    </div>
92
93    <div class="body-text">
94      <p>Let's start by loading a very simple nibfile from the Clozure
95        CL Listener window. Start by launching the Clozure CL
96        application.</p>
97
98      <p>In the same directory as this HOWTO file, you'll find a
99        nibfile named "hello.nib". This is an extremely simple nibfile
100        that creates a single Cocoa window with a greeting in it. We'll
101        use forms typed into the Listener window to load it.</p>
102
103      <p>We're going to call the Objective-C class
104        method <code>loadNibFile:externalNameTable:withZone:</code> to
105        load the nibfile into memory, creating the window that is
106        described in the file. First, though, we need to set up some
107        data structures that we'll pass to this method.</p>
108
109      <p>The arguments
110        to <code>loadNibFile:externalNameTable:withZone:</code> are a
111        pathname, a dictionary object, and a memory zone. As with every
112        Objective-C method call, we also pass the object that receives
113        the message, which in this case is the class NSBundle.</p>
114
115      <p>The pathname is just a reference to the nibfile we want to
116        load. The dictionary holds references to objects. In this
117        first simple example, we'll use it only to identify the
118        nibfile's owner, which in this case is the application
119        itself. The zone is a reference to the area of memory where
120        the nibfile objects will be allocated.</p>
121
122      <p>Don't worry if none of this makes sense to you; the code to
123        create these objects is simple and straightforward, and should
124        help clarify what's going on.</p>
125
126      <div class="section-head">
127        <h3>1. Get the Zone</h3> 
128      </div>
129
130      <p>First, we'll get a memory zone. We'll tell Cocoa to allocate
131        the nibfile objects in the same zone that the application
132        uses, so getting a zone is a simple matter of asking the
133        application for the one it's using.</p>
134
135      <p>Before we can ask the application anything, we need a
136        reference to it. We'll ask the class NSApplication to give us a
137        reference to the running application.</p>
138
139      <p>Start by changing to the CCL package; most of the utility
140        functions we'll use are defined in that package:</p>
141
142      <pre>
143        ? (in-package :ccl)
144        #&lt;Package "CCL"&gt;
145      </pre>
146
147      <p>Next, get a reference to the NSApplication class:</p>
148
149      <pre>
150        ? (setf  *my-app*
151                 (let* ((class-name (%make-nsstring "NSApplication"))
152                        (appclass (#_NSClassFromString class-name)))
153                   (#/release class-name)
154                   (#/sharedApplication appclass)))
155        #&lt;LISP-APPLICATION &lt;LispApplication: 0x1b8de0&gt; (#x1B8DE0)&gt;
156      </pre>
157
158      <p>Let's review this form step-by-step.</p>
159
160      <p>First of all, it's going to store the returned application
161      object in the variable <code>*my-app*</code>, so that we have it
162      convenient for later use.</p>
163
164      <p>We need an <code>NSString</code> object that contains the
165      name of the application class, so the code allocates one by
166      calling <code>%make-nsstring</code>. The <code>NSString</code>
167      object is a dynamically-allocated foreign object, not managed by
168      Lisp's garbage-collector, so we'll have to be sure to release it
169      later.</p>
170
171      <p>The code next uses the class-name to get the
172      actual <code>NSApplication</code> class object, by
173      calling <code>#_NSClassFromString</code>.</p>
174
175      <p>Finally, after first releasing the <code>NSString</code>
176      object, it calls <code>#/sharedApplication</code> to get the
177      running application object, which turns out to be an instance
178      of <code>LispApplication</code>.</p>
179
180        <p>Voilà! We have a reference to the running Clozure CL
181          application object! Now we can ask it for its zone, where it
182          allocates objects in memory:</p>
183
184        <pre>
185          ? (setf *my-zone* (#/zone *my-app*))
186          #&lt;A Foreign Pointer #x8B000&gt;
187        </pre>
188
189        <p>Now we have a reference to the application's zone, which is
190          one of the parameters we need to pass
191          to <code>loadNibFile:externalNameTable:withZone:</code>.</p>
192
193        <div class="section-head">
194          <h3>2. Make a Dictionary</h3> 
195        </div>
196
197        <p>The dictionary argument
198          to <code>loadNibFile:externalNameTable:withZone:</code> is
199          used for two purposes: to identify the nibfile's owner, and
200          to collect toplevel objects.</p>
201
202        <p>The nibfile's owner becomes the owner of all the toplevel
203          objects created when the nibfile is loaded, objects such as
204          windows, buttons, and so on. A nibfile's owner manages the
205          objects created when the nibfile is loaded, and provides a
206          way for your code to get references to those objects. You
207          supply an owner object in the dictionary, under the
208          key <code>"NSNibOwner"</code>.</p>
209
210        <p>The toplevel objects are objects, such as windows, that are
211          created when the nibfile is loaded. To collect these, you
212          can pass an <code>NSMutableArray</code> object under the
213          key <code>"NSNibTopLevelObjects"</code>.</p>
214
215        <p>For this first example, we'll pass an owner object (the
216          application object), but we don't need to collect toplevel
217          objects, so we'll omit
218          the <code>"NSNibTopLevelObjects"</code> key.</p>
219
220        <pre>
221          ? (setf *my-dict*
222                  (#/dictionaryWithObject:forKey: (@class ns-mutable-dictionary)
223                                                  *my-app*
224                                                  #@"NSNibOwner"))
225          #&lt;NS-MUTABLE-DICTIONARY {
226                                  NSNibOwner = &lt;LispApplication: 0x1b8e10&gt;;
227                                  } (#x137F3DD0)&gt;
228           
229          </pre>
230
231        <div class="section-head">
232          <h3>3. Load the Nibfile</h3> 
233        </div>
234
235        <p>Now that we have the zone and the dictionary we need, we
236        can load the nibfile. We just need to create an NSString with
237        the proper pathname first:</p>
238
239        <pre>
240          ? (setf *nib-path*
241                  (%make-nsstring
242                     (namestring "/usr/local/openmcl/ccl/examples/cocoa/nib-loading/hello.nib")))
243          #&lt;NS-MUTABLE-STRING "/usr/local/openmcl/ccl/examples/cocoa/nib-loading/hello.nib" (#x13902C10)&gt;
244        </pre>
245
246        <p>Now we can actually load the nibfile, passing the method
247        the objects we've created:</p>
248
249        <pre>
250          ? (#/loadNibFile:externalNameTable:withZone:
251                  (@class ns-bundle)
252                  *nib-path*
253                  *my-dict*
254                  *my-zone*)
255          T
256        </pre>
257
258        <p>The window defined in the "hello.nib" file should appear
259        on the
260        screen. The <code>loadNibFile:externalNameTable:withZone:</code>
261        method returns <code>T</code> to indicate it loaded the
262        nibfile successfully; if it had failed, it would have
263        returned <code>NIL</code>.</p>
264
265        </div>
266
267      </body>
268    </html>
269
Note: See TracBrowser for help on using the repository browser.