• Keine Ergebnisse gefunden

Dynamic Loading

Im Dokument Oriented Software (Seite 141-147)

An Objective C program can load and link new classes and categories while it's running.

The new code is incorporated into the program and treated identically to classes and categories loaded at the start.

Dynamic loading can be used to do a lot of different things. For example, device drivers written with the NeXTSTEP Device Driver KifM (a Release 3.1 addition) are dynamically loaded into the kernel. Adaptors for database servers are dynamically loaded by the Database Kit.

124 Chapter 4: The Run-Time System

In the NeXTSTEP environment, dynamic loading currently finds its favored use in customizing applications. You can allow others to write modules that your program will load at run time-much as the NeXTSTEP Interface Builder loads custom palettes, the Preferences application loads custom displays, and the Workspace Manager loads data inspectors. The loadable modules extend what your application can do. They contribute to it in ways that you permit, but could not have anticipated or defined yourself. You provide the framework, but others provide the code.

Dynamically loaded modules that customize an application generally come with their own user interface-perhaps their own windows, but more likely objects that draw in windows you provide. When the code is loaded and objects are instantiated or unarchived, the interface to the custom portion of the application is presented on-screen along with the rest of the user interface.

The Preferences application, for example, has a window with a scrollable list of buttons along the top, plus a display area beneath the buttons. Each button controls the presentation of a different set of options within the display area; clicking a button causes its options to be displayed. Each dynamically loadable module provides a display that can be presented in the window, along with an image for the button and the code to handle user actions and set preferences. The Preferences window illustrated below shows the localization button highlighted and, beneath it, the display of localization options.

Figure 20. The Preferences Application

Dynamic Loading 125

Bundles

Classes and categories are dynamically loaded and linked by calling the

objc_loadModulesO function. They can be unlinked and unloaded again by calling objc_unloadModulesO. However, once code is loaded, it typically remains in place;

there's little reason to unload it.

These two functions are part of the Objective C run-time system and provide the basic methodology for dynamic loading and unloading. They're documented in the NeXTSTEP General Reference manual. However, the NeXTSTEP environment also provides another, more convenient interface for dynamic loading-one that's object-oriented and integrated with related services. The loading task can be assigned to an NXBundle object.

NXBundles correspond to directories where programs store resources they'll refer to at run time. Each object manages one directory. The directory "bundles" the resources and makes them available to the NXBundle object and, through the object, to the program. The directory might contain image data, sound files, objects that were archived into so-called

"nib files" by Interface Builder, tables of character strings, and other resources. It can also contain a file of executable code.

An NXBundle object is initialized to a bundle directory with the initForDirectory: method as shown below (though, of course, you'd rarely use a hard-wired path like this):

char *path

=

I/LocalLibrary/Preferences/Music.preferences";

NXBundle *myBundle

=

[[NXBundle alloc] initForDirectory:path];

An NXBundle can do two things with the information stored in the bundle directory:

• Dynamically load the executable code and return class objects for the newly loaded classes

• Find resources that match the user's language preference and make them available to the application

These two things go together; the whole point of an NXBundle is to combine them in a single facility. Dynamically loaded code doesn't stand on its own. It typically requires the support of various resource files-archived instances of the bundled classes, character strings that the code displays to users, bitmap images to place within the display, and so on.

Code and resources are grouped together in the same directory and are managed together by the same NXBundle object.

126 Chapter 4: The Run-Time System

Localized Resources

Typically, a bundle directory packages a file of loadable code with all the resources that the code requires. Some resources in the bundle might occur in various alternative forms

"localized" to a particular language or region of the world. For example, the English string

"Select All" might have counterparts in Spanish ("Seleccionar todo"), German ("Alles auswahlen"), French ("Tout selectionner"), Swedish ("Markera alIt"), and other languages.

Localized resources are kept in subdirectories of the bundle directory. Each subdirectory is named after a language and carries a ".lproj" extension (for "language project"). For example, there might be Swedish.lproj, English.lproj, and Tagalog.lproj subdirectories.

Each subdirectory has a matched set of files. If the user sets the language preference to Swedish, the application will use the files in Swedish.lproj. If the preference is set to English, English.lproj files will be used. When asked for a resource, an NXBundle looks in the subdirectory that matches the current preference.

The figure below illustrates the layout of a possible bundle for the Preferences application.

The Music file holds the loadable code and Music.tiff holds the bitmap image (in Tag Image File Format) that will be displayed on the button at the top of the window. The rest of the files are localized and located in ".lproj" subdirectories.

Music.preferences Music Music.tiff

French.lproj

1

Music.nib Composers. strings Compositions.strings Samples.snd English.lp·roj

1

Music.nib Composers.strings

Compositions.strings Samples.snd Swedish.lproj

1

Music.nib Composers.strings

Compositions.strings Samples.snd Figure 21. A Bundle Directory

Dynamic Loading 127

Note: Language preferences are set using the Preferences application, as shown above in Figure 20. The application not only sets the preference, it is itself localized and reflects the current choice. In the figure, the language preference is set to Spanish and, accordingly, Spanish is displayed in the window.

Loadable Code

The loadable code in a bundle directory must be in a file with the same name as the directory (minus any extension on the directory name) and it must contain nothing but compiled class and category definitions.

Bundled code is not localized. Rather, it's kept free of any content that would vary depending on the language or location where the software is used. This content is extracted from the code and put in resource files within the ".lproj" subdirectories. The same NXBundle object that loads the executable code can find the required resources at run time.

Dynamic loading therefore should not be seen as the isolated task of loading and linking class and category code. It also includes loading the objects, images, strings, sounds, and other resources that are required at run time. The decision of which resources to load must be dynamic for it depends on information available only at run time-the user's language preference.

Loading Bundled Code

When requested, an NXBundle returns class objects for the classes bundled within its directory. It waits until it receives the first request to load the bundled code. This message, for example, asks an NXBundle for the Ivlozart class:

Class composer = [myBundle classNamed:"Mozart"];

If the executable code stored in the bundle had not yet been loaded, this message would load it. All bundled classes are located in one file and are loaded at the same time. If the file doesn't contain the requested class, c1assNamed: returns nil.

128 Chapter 4: The Run-Time System

The classNamed: method finds a specific class within the bundle, one that you request by name. Typically, however, an application needs to find only one class from the dynamically loaded file (at least initially), and it won't know or care what the class is named. The principal Class method returns this class:

Class head

=

[myBundle principalClass];

Like classNamed:, principal Class dynamically loads the bundled code if it hasn't already been loaded.

A set of bundled classes often supports a small subnetwork of objects that can be attached to the larger object network already in place. The connection is established through just one object, an instance of the principal class. That object might have methods to return other objects that the application can talk to, but typically all messages from the application to the subnetwork are funneled through the one instance.

The NXBundle expects the principal class to be the first one encountered in the executable file. When several classes are linked into a dynamically loadable file, the principal class should be the first one listed on the ld command line. For example, this command makes DiscJockey the principal class in the Music bundle:

ld -0 Music -r DiscJockey.o Bach.o Mozart.o Coltrane.o . . .

Each application has a choice to make regarding when to load bundled code. It can load the code at start-up before the interaction with the user begins, or it can wait until the user requests it. There are benefits to waiting. For example, when it encounters a bundle of loadable code, the Preferences application immediately creates a button for it and puts the button in the scrollable list at the top of the window. It takes the image for the button from the bundle directory (Music.tiffin Figure 21 above). However, it doesn't dynamically load the bundled code (the Music file Figure 21) until the user clicks the button. Code that isn't used isn't loaded.

For some applications, the user's request can be even more explicit. For example, you might present the user with a panel that displays file icons for each bundle containing dynamically loadable code. The panel might even display some information about each bundle, information supplied by the customizer in the bundle directory. When the user double-clicks an icon, the application would load it and display its user interface on-screen.

No matter what triggers dynamic loading, when your application is ready to start using the bundled code, the principalClass method will load it.

Dynamic Loading 129

Im Dokument Oriented Software (Seite 141-147)