An NSBundle object helps you access the code and resources in a bundle directory on disk. Apple uses bundles to represent apps, frameworks, plug-ins, and many other specific types of content. Bundles organize their contained resources into well-defined subdirectories, and bundle structures vary depending on the platform and the type of the bundle. By using a bundle object, you do not have to know the structure of a bundle to access its resources. The bundle object provides a single interface for locating items, taking into account the bundle structure, user preferences, available localizations, and other relevant factors.
Language
- Swift
- Objective-C
SDKs
- iOS 8.0+
- macOS 10.10+
- tvOS 9.0+
- watchOS 2.0+
Overview
Any executable can use a bundle object to locate resources. You use an NSBundle object whenever you need to locate resources, either inside an app’s bundle or in a known bundle located elsewhere. You do not use a bundle object to locate files in a container directory or in other parts of the file system.
The general pattern for using a bundle object is as follows:
Create a bundle object for the intended bundle directory.
Use the methods of the bundle object to locate or load the needed resource.
Use other system APIs to interact with the resource.
Some types of frequently used resources can be located and opened without a bundle. When loading images, store your images in asset catalogs and load them using the init(named:) methods of UIImage or NSImage. For string resources, use the NSLocalizedString family of macros to load individual strings instead of loading the entire .strings file yourself.
Note
Unlike some other Foundation classes with corresponding Core Foundation names (such as NSString and CFString), NSBundle objects cannot be cast (“toll-free bridged”) to CFBundle references. If you need functionality provided in CFBundle, you can still create a CFBundle and use the CFBundle API. See Interchangeable Data Types for more information on toll-free bridging.
Finding and Opening a Bundle
Before you can locate a resource, you must first specify the bundle containing that resource. The NSBundle class has many methods for creating bundle objects, but the one you use most often is the main() method. The main bundle represents the bundle directory that contains the currently executing code. So for an app, the main bundle object gives you access to the resources that shipped with your app.
If your app interacts directly with plug-ins, frameworks, or other bundled content, you can use other methods of this class to create appropriate bundle objects. You can always create bundle objects from a known URL or path, but there are other methods that make it easier to access bundles your app is already using. For example, if you link to a framework, you can use the init(for:) method to locate the framework bundle based on a class defined in that framework.
// Get the app's main bundle
let mainBundle = NSBundle.mainBundle()
// Get the bundle containing the specified private class.
let myBundle = NSBundle.init(forClass: NSClassFromString("MyPrivateClass")!)
Locating Resources in a Bundle
You use an NSBundle object to obtain the location of specific resources inside the bundle. When looking for resources, you provide the name of the resource and its type at a minimum. For resources in a specific subdirectory, you can also specify that directory. After locating the resource, the bundle routines return a path string or URL that you can use to open the file.
Bundle objects follow a specific search pattern when looking for resources on disk. Global resources—that is, resources not in a language-specific .lproj directory—are returned first, followed by region- and language-specific resources. This search pattern means that the bundle looks for resources in the following order:
Global (nonlocalized) resources
Region-specific localized resources (based on the user’s region preferences)
Language-specific localized resources (based on the user’s language preferences)
Development language resources (as specified by the
CFBundleDevelopmentRegionkey in the bundle’s Info.plist file)
Because global resources take precedence over language-specific resources, you should never include both a global and localized version of a given resource in your app. When a global version of a resource exists, language-specific versions are never returned. The reason for this precedence is performance. If localized resources were searched first, the bundle object might waste time searching for a nonexistent localized resource before returning the global resource.
Important
Bundle objects always consider case when searching for resource files, even on file systems that support case-insensitive filenames. Always make sure that you specify filenames with case sensitivity in mind.
When locating resource files, the bundle object automatically considers many standard filename modifiers when determining which file to return. Resources may be tagged for a specific device (~iphone, ~ipad) or for a specific screen resolution (@2x, @3x). Do not include these modifiers when specifying the name of the resource you want. The bundle object selects the file that is most appropriate for the underlying device.
Understanding Bundle Structures
Bundle structures vary depending on the target platform and the type of bundle you are building. The NSBundle class hides this underlying structure in most (but not all) cases. Many of the methods you use to load resources from a bundle automatically locate the appropriate starting directory and look for resources in known places. You can also use the methods and properties of this class to get the location of known bundle directories and to retrieve resources specifically from those directories.
For information about the bundle structure of iOS and macOS apps, see Bundle Programming Guide. For information about the structure of framework bundles, see Framework Programming Guide. For information about the structure of macOS plug-ins, see Code Loading Programming Topics.