< Previous PageNext Page > Hide TOC

Loading and Unloading Executable Code

Most applications use only the code from their own main executable file. However, if you are developing an application that supports plug-ins or other types of loadable bundles, you need to know how to load the code from these separate bundles dynamically. Both CFBundle and NSBundle provide facilities for loading code from a bundle. Depending on your needs, you may use one or both of these objects in your coding.

The key to loading code from an external bundle is finding an appropriate entry point into the bundle’s executable file. As with other plug-in schemes, this requires some coordination between the application developer and plug-in developer. You can publish a custom API for bundle’s to implement or define a formal plug-in interface. In either case, once you have an appropriate bundle or plug-in, you need a way to access the functions or classes implemented by the external code.

Note: Another option for loading Mach-O code directly is to use the NSModule loading routines. However, these routines typically require more work to use and are less preferable than CFBundle or NSBundle. For more information, see Mac OS X ABI Mach-O File Format Reference in Mac OS X Documentation or see the NSModule man pages.

Contents:

Loading Functions
Loading Objective-C Classes
Unloading Bundles


Loading Functions

If you are working in C, C++, or even in Objective-C, you can publish your interface as a set of C-based symbols, such as function pointers and global variables. Using the CFBundle interfaces, you can load references to those symbols from a bundle’s executable file.

You can retrieve symbols using any of several CFBundle interfaces. To retrieve function pointers, call either CFBundleGetFunctionPointerForName or CFBundleGetFunctionPointersForNames. To retrieve a pointer to a global variable, call CFBundleGetDataPointerForName or CFBundleGetDataPointersForNames. For example, suppose a loadable bundle defines the function shown in Listing 1.

Listing 1  An example function for a loadable bundle

    // Add one to the incoming value and return it.
    long addOne(short number)
    {
        return ( (long)number + 1 );
    }

Given a CFBundle object for the loadable bundle, you would need to search for the desired function before you could use it in your code. Listing 2 shows a code fragment that illustrates this process. In this example, the myBundle variable is a CFBundle object pointing to the bundle.

Listing 2  Finding a function in a loadable bundle

// Function pointer.
AddOneFunctionPtr addOne = NULL;
 
// Value returned from the loaded function.
long result;
 
// Get a pointer to the function.
addOne = (void*)CFBundleGetFunctionPointerForName(
            myBundle, CFSTR("addOne") );
 
    // If the function was found, call it with a test value.
if (addOne)
{
    // This should add 1 to whatever was passed in
    result = addOne ( 23 );
}

Loading Objective-C Classes

If you are writing a Cocoa application, you can load the code for an entire class using the methods of NSBundle. The NSBundle methods for loading a class are aimed squarely for Objective-C developers and cannot be used to load classes written in C++ or other object-oriented languages.

If a loadable bundle defines a principal class, you can load it using the principalClass method of NSBundle. The principalClass method uses the NSPrincipalClass key of the bundle’s Info.plist file to identify and load the desired class. Using the principal class alleviates the need to agree on specific naming conventions for external classes, instead letting you focus on the behavior of those interfaces. For example, you might use an instance of the principal class as a factory for creating other relevant objects.

If you want to load an arbitrary class from a loadable bundle, call the classNamed: method of NSBundle. This method searches the bundle for a class matching the name you specify. If the class exists in the bundle, the method returns the corresponding Class object, which you can then use to create instances of the class.

Listing 3 shows you a sample method for loading a bundle’s principal class.

Listing 3  Loading the principal class of a bundle

- (void)loadBundle:(NSString*)bundlePath
{
    Class exampleClass;
    id newInstance;
    NSBundle *bundleToLoad = [NSBundle bundleWithPath:bundlePath];
    if (exampleClass = [bundleToLoad principalClass])
    {
        newInstance = [[exampleClass alloc] init];
        // [newInstance doSomething];
    }
}

For more information about NSBundle methods, see the NSBundle class description in the Foundation reference.

Unloading Bundles

You cannot currently unload the contents of an NSBundle object. You can unload the contents of a CFBundle object using CFBundleUnloadExecutable. If your bundle may be unloaded, you need to ensure that string constants are handled correctly by setting an appropriate compiler flag.

When you compile a bundle with a minimum deployment target of Mac OS X 10.2 (or later), the compiler automatically switches to generating “truly-constant” strings in response to CFSTR("..."). This can also be achieved by compiling with the flag -fconstant-cfstrings. Constant strings have many benefits and should be used when possible, however if you reference constant strings after the executable containing them is unloaded, the references will be invalid and will cause a crash. This might happen even if the strings have been retained, for example, as a result of being put in data structures, retained directly, and, in some cases, even copied. Rather than trying to make sure all such references are cleaned up at unload time (and some references might be created within the libraries, making them hard to track), it is best to compile unloadable bundles with the flag -fno-constant-cfstrings.



< Previous PageNext Page > Hide TOC


© 2003, 2005 Apple Computer, Inc. All Rights Reserved. (Last updated: 2005-11-09)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.