Before you can access a bundle’s resources, you must first obtain an appropriate NSBundle
or CFBundle
object. The following sections outline the different ways you create these objects from your code.
Opening the Main Bundle
Locating Bundles by Path
Locating Bundles in Known Directories
Locating Bundles by Identifier
Searching for Related Bundles
The main bundle is the bundle that contains your running code. This is the most commonly used bundle for any program and is what you use to load your strings, images, and other resource files. Because it is a meta bundle, the main bundle is the easiest to retrieve. To get it, call either CFBundleGetMainBundle
function or use the mainBundle
class method of NSBundle
. Listing 1 shows an example of loading the main bundle from a Carbon application.
Listing 1 Locating the main bundle from Core Foundation
CFBundleRef mainBundle; |
// Get the main bundle for the app |
mainBundle = CFBundleGetMainBundle(); |
Listing 2 shows this same code example written in Objective-C and using the NSBundle
class.
Listing 2 Locating the main bundle from Cocoa
NSBundle* mainBundle; |
// Get the main bundle for the app. |
mainBundle = [NSBundle mainBundle]; |
When getting the main bundle it is still a good idea to make sure the value you get back represents a valid bundle. In particular, you might get a NULL
value for the main bundle in the following situations:
If a program is not bundled, attempting to get the main bundle might return a NULL
value. The bundle code may try to create a main bundle for you to represent your program’s contents but in some exceptional cases, it cannot and returns NULL
.
If the agent launching the program does not specify the full path to the program's executable in the argv
parameters, the main bundle value might be NULL
. Bundles rely on either the path to the executable being in argv[0]
or the presence of the executable's path in the PATH
environment variable. If neither of these is present, the bundle routines might not be able to find the main bundle directory. Programs launched by xinetd
often experience this problem when xinetd
changes the current directory to /
.
If you want to access a bundle other than your main bundle, one way to create an appropriate bundle object is with a path to the bundle. The CFBundleCreate
function in Core Foundation takes a CFURLRef
specifying the path to the bundle and returns a corresponding CFBundle
data type. Similarly, you can use the bundleWithPath:
method of NSBundle
to create a bundle object from an NSString
.
Listing 3 shows an example of how to create a CFBundle
from a string specifying the path. The main trick is to convert the string to a CFURLRef
object so that it can be passed to the CFBundleCreate
function.
Listing 3 Locating a Core Foundation bundle using its path
CFURLRef bundleURL; |
CFBundleRef myBundle; |
// Make a CFURLRef from the CFString representation of the |
// bundle’s path. |
bundleURL = CFURLCreateWithFileSystemPath( |
kCFAllocatorDefault, |
CFSTR("/Local/Library/MyBundle.bundle"), |
kCFURLPOSIXPathStyle, |
true ); |
// Make a bundle instance using the URLRef. |
myBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); |
// Any CF objects returned from functions with "create" or |
// "copy" in their names must be released by us! |
CFRelease( bundleURL ); |
CFRelease( myBundle ); |
The preceding example can be rewritten for Cocoa using the code shown in Listing 4.
Listing 4 Locating a Cocoa bundle using its path
NSBundle* myBundle; |
// Get the main bundle for the app. |
myBundle = [NSBundle bundleWithPath:@"/Local/Library/MyBundle.bundle"]; |
Even if you do not know the exact path to a bundle, there are still situations where you can search for it by name. One example is if your application contains several embedded plug-ins in a PlugIns
directory. Because this directory is inside of your application bundle, you can use the CFBundle
functions for locating resources to get the path to each plug-in.
To load a set of plug-ins, use the CFBundleCreateBundlesFromDirectory
function to create new CFBundle
objects for all of the plug-ins in a given directory. Listing 5 is similar to the previous example, but this time the code retrieves CFBundle
objects for all of the plug-ins in the application’s PlugIns
directory.
Listing 5 Obtaining bundle references for a set of plug-ins
CFBundleRef mainBundle = CFBundleGetMainBundle(); |
CFURLRef plugInsURL; |
CFArrayRef bundleArray; |
// Get the URL to the application’s PlugIns directory. |
plugInsURL = CFBundleCopyBuiltInPlugInsURL(mainBundle); |
// Get the bundle objects for the application’s plug-ins. |
bundleArray = CFBundleCreateBundlesFromDirectory( kCFAllocatorDefault, |
plugInsURL, NULL ); |
// Release the CF objects |
CFRelease( plugInsURL ); |
CFRelease( bundleArray ); |
Bundle identifiers make it possible to locate already loaded bundles at runtime. This is a useful way for your code to locate its own bundle at runtime. Storing a bundle identifier can be more efficient than storing a reference to the bundle itself. When you need to access the bundle again, you can use the identifier to retrieve the CFBundle
object.
Each bundle you create should have a bundle identifier in its information property-list (Info.plist
) file. The CFBundleIdentifier
key contains the bundle identifier string, which traditionally uses Java-style package naming conventions. For example, a Finder plug-in from Apple might use the string com.apple.Finder.MyGetInfoPlugin
as its bundle identifier. Including the domain name of your company in the string helps avoid collisions with bundle developers in other companies.
Listing 6 shows how to retrieve a bundle using its bundle identifier. Remember that a bundle identifier can only be used to locate an existing CFBundle
instance (including the main bundle and bundles for all statically linked frameworks). If your bundle has been opened and its code is running, then you can locate it using its bundle identifier.
Listing 6 Locating a bundle using its identifier
CFBundleRef requestedBundle; |
// Look for a bundle using its identifier |
requestedBundle = CFBundleGetBundleWithIdentifier( |
CFSTR("com.apple.Finder.MyGetInfoPlugIn") ); |
You can also locate bundles by their identifier in Cocoa. The NSBundle
class defines the class method bundleWithIdentifier:
to find and return an existing bundle.
If you are writing a Cocoa application, you can obtain a list of bundles related to the application by calling the allBundles
and allFrameworks
class methods of NSBundle. These methods create an array of NSBundle
objects corresponding to the bundles or frameworks currently in use by your application. You can use these methods as convenience functions rather than maintain a collection of loaded bundles yourself.
The bundleForClass:
class method is another way get related bundle information in a Cocoa application. This method returns the bundle in which a particular class is defined. Again, this method is mostly for convenience so that you do not have to retain a pointer to an NSBundle
object that you may use only occasionally.
© 2003, 2005 Apple Computer, Inc. All Rights Reserved. (Last updated: 2005-11-09)