The applications we’ve built have
not allowed the user to create and store a lot of new data. Quite a few
types of applications, however, do need to store a substantial amount of
new information. Consider some of Apple’s applications, such as Notes
and Contacts. These are data management applications whose main function
is to reliably store and retrieve data for the user. Where does this
data go when the application is not running? Just like with a desktop
application, iPhone applications persist their data to the file system.
In creating the iOS SDK, Apple
introduced a wide range of restrictions designed to protect users from
malicious applications harming their devices. The restrictions are
collectively known as the application sandbox. Any application you
create with the SDK exists in a sandbox. There is no opting out of the
sandbox and no way to get an exemption from the sandbox’s restrictions.
Some of these
restrictions affect how application data is stored and what data can be
accessed. Each application is given a directory on the device’s file
system, and applications
are restricted to reading and writing files in their own directory.
This means a poorly behaved application can, at worst, wipe out its own
data but not the data of any other application.
It also turns out that this
restriction is not terribly limiting. The information from Apple’s
applications, such as contacts, calendars, and the photo and music
libraries, is for the most part already exposed through APIs in the iOS
SDK.
Watch Out!
With each version of the
iOS SDK, Apple has been steadily ramping up what you can’t do because of
the application sandbox, but parts of the sandbox are still enforced
via policy rather than as technical restrictions. Just because you find a
location on the file system where it is possible to read or write files
outside the application sandbox doesn’t mean you should. Violating the
application sandbox is one of the surest ways to get your application
rejected from the iTunes Store.
Storage Locations for Application Data
Within an
application’s directory, four locations are provided specifically for
storing the application’s data: the Library/Preferences, Library/Caches,
Documents, and tmp directories.
By the Way
When you run an
application in the iPhone Simulator, the application’s directory exists
on your Mac in /Users/<your user>/Library/Applications
Support/iPhone Simulator/<Device OS Version>/Applications. There
are any number of applications in this directory, each with a directory
named after a unique application ID (a series of characters with dashes)
that is provided by Xcode. The easiest way to find the directory of the
current application you are running in the iPhone Simulator is to look
for the most recently modified application directory. Take a few minutes
now to look through the directory of a couple applications from
previous hours.
You encountered the
Library/Preferences directory earlier this hour. It’s not typical to
read and write to the Preferences directory directly. Instead, you use
the NSUserDefaults API. The Library/Caches, Documents, and tmp
directories are, however, intended for direct file manipulation. The
main difference between them is the intended lifetime of the files in
each directory.
The Documents directory is
the main location for storing application data. It is backed up to the
computer when the device is synced with iTunes, so it is important to
store any data users would be upset to lose in the Documents directory.
The
Library/Caches directory is used to cache data retrieved from the
network or from any computationally expensive calculation. Files in
Library/Caches persist between launches of the application, and caching
data in the Library/Caches directory can be an important technique used
to improve the performance of an application.
Lastly, any data you want to
store outside of the device’s limited volatile memory, but that you do
not need to persist between launches of the application, belongs in the
tmp directory. The tmp directory is a more transient version of
Library/Caches; think of it as a scratch pad for the application.
Watch Out!
Applications are
responsible for cleaning up all the files they write, even those written
to Library/Caches or tmp. Applications are sharing the limited file
system space (typically 4GB to 32GB) on the device. The space an
application’s files take up is not available for music, podcasts,
photos, and other applications. Be judicious in what you choose to
persistently store, and be sure to clean up any temporary files created
during the lifetime of the application.
File Paths
Every file in an iPhone
file system has a path, which is the name of its exact location on the
file system. For an application to read or write a file in its sandbox,
it needs to specify the full path of the file.
Core Foundation provides a C function called NSSearchPathForDirectoriesInDomains
that returns the path to the application’s Documents or Library/Caches
directory. Asking for other directories from this function can return
multiple directories, so the result of the function call is an NSArray object. When this function is used to get the path to the Documents or Library/Caches directory, it returns exactly one NSString in the array, and the NSString of the path is extracted from the array using NSArray’s objectAtIndex method with an index of 0.
NSString provides a method for joining two path fragments together called stringByAppendingPathComponent. By putting the result of a call to NSSearchPathForDirectoriesInDomains
together with a specific filename, it is possible to get a string that
represents a full path to a file in the application’s Documents or
Library/Caches directory.
Suppose, for
example, your next blockbuster iPhone application calculates the first
100,000 digits of pi, and you want the application to write the digits
out to a cache file so that they won’t need to be calculated again. To
get the full path to this file’s location, you need to first get the
path to the Library/Caches directory and then append the specific
filename to it:
NSString *cacheDir =
[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
NSUserDomainMask, YES) objectAtIndex: 0];
NSString *piFile = [cacheDir stringByAppendingPathComponent:@"American.pi"];
To get a path to a file in the Documents directory, use the same approach but with NSDocumentDirectory as the first argument to NSSearchPathForDirectoriesInDomains:
NSString *docDir =
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) objectAtIndex: 0];
NSString *scoreFile = [docDir stringByAppendingPathComponent:@"HighScores.txt"];
Core Foundation provides another C function called NSTemporaryDirectory that returns the path of the application’s tmp directory. As before, this can be used to get a full path to a file:
NSString *scratchFile =
[NSTemporaryDirectory() stringByAppendingPathComponent:@"Scratch.data"];