Reader beware: this post is part of the older "Objective-C era" on Cocoa with Love. I don't keep these articles up-to-date so the code may be broken or superceded by newer APIs. There's some good information but there's also some opinions I no longer endorse – keep a skeptical mind. Read "A new era for Cocoa with Love" for more.
A simple post this week but one which optimizes a common task: locating the application support directory for the current application, creating it if it doesn't exist. The result makes accessing the current application's support directory a single line and provides a structure for locating and creating folders at other standard locations with similar ease.
The Application Support Directory
On the Mac, the correct location to store persistent user-related files for your application is in a directory with the same name as your application in the Application Support directory for the current user.
As an example, if the current user "person" runs an application named "ExampleApp" it would store such files in the following location:
On iPhone OS devices, the running application gets its own copy of the Library directory, so you could write files wherever you choose within this. However, I use the same code on both platforms for consistency and there is no real penalty in doing this. For an iPhone OS device then, the path to the application support directory would look like this:
12345678-AAAA-BBBB-CCCC-0123456789AB is whatever UUID has been assigned to your application.
The application support directory is only for user-related persistent files. If you want to store user-related preferences, it is generally better to can store them in the NSUserDefaults.
Getting paths correctly
The correct way to get the path to the Application Support directory is to use the
NSSearchPathForDirectoriesInDomains function passing
NSApplicationSupportDirectory for the search path and
NSUserDomainMask for the domain.
This can be done in one line but on its own, it is only ever part of the solution.
NSSearchPathForDirectoriesInDomains can return a path to the Application Support directory, it does not guarantee that the application support directory exists. For an iPhone OS device, it almost certainly won't exist the first time you run the application.
Further, we need to append the name of the current application to this path and create this application-specific subdirectory if needed.
Finally, we need to handle all of this in a way that is tolerant of errors including failure to create the directory or existence of files where we need a directory to go.
A simple idea — get the application support directory — turns out to be a multi-step operation.
Design of the solution
The solution that I use in many of my applications is based around a method with the following declaration:
This is a flexible method that can be used for resolving/creating a directory/subdirectory at any standard location searchable by
The first two parameters are the parameters passed to
NSSearchPathForDirectoriesInDomains, the third parameter is a subpath to append to the result from
NSSearchPathForDirectoriesInDomains (which we can use to append the current application's name to get our application specific subdirectory). The final parameter is used to return information about any of the three errors that can occur (no path found, file exists at directory location or unable to create directories).
I further supplement this with a convenience method to invoke this with all the appropriate parameters for creating the application support directory:
On error, this method simply logs any error result using
In my solution, both of these methods are part of a category on
NSFileManager. There is no technical requirement that it be a category on
NSFileManager but these methods do use
NSFileManager internally and do share the same goals of providing access to directories within the filesystem. Further refinements could also add a URL version based on the NSFileManager method
-URLsForDirectory:inDomains: which would make the association less arbitrary.
I've omitted the creation of the error objects for space but otherwise the implementation is as follows:
I've noted that we "
Normally only need the first path". If you pass multiple values ORed together for the domain mask (e.g.
NSUserDomainMask | NSLocalDomainMask) then this assumption will not be true. If your program needs to handle multiple directories in this way, you'll need to add appropriate handling of multiple results.
Finally, we have the implementation of the
As you can see, it pulls the application name out of the main bundle's
infoDictionary and uses this to create the Application Support directory.
The end result is that you can get the path to the application support directory with the following line:
You can download the complete category here: NSFileManager_DirectoryLocations.zip (6kb)
I like it when a task that can be unambiguously described in a simple sentence ("Get the path to the application support directory.") is correspondingly achieved in a single line.
The code presented in this post implements a simple set of steps but since I need to do this in most applications, it is one of my most commonly used categories.
Porting a Mac program to Windows using The Cocotron
A look at how malloc works on the Mac