views:

1163

answers:

1

I am posting this question because I had a complete answer for this written out for another post, when I found it did not apply to the original but I thought was too useful to waste. Thus I have also made this a community wiki, so that others may flesh out question and answer(s). If you find the answer useful, please vote up the question - being a community wiki I should not get points for this voting but it will help others find it

How can I get a path into which file writes are allowed on the iPhone? You can (misleadingly) write anywhere you like on the Simulator, but on the iPhone you are only allowed to write into specific locations.

+6  A: 

There are three kinds of writable paths to consider - the first is Documents, where you store things you want to keep and make available to the user through iTunes (as of 3.2):

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

Secondly, and very similar to the Documents directory, there is the Library folder, where you store configuration files and writable databases that you also want to keep around, but you don't want the user to be able to mess with through iTunes:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

Note that even though the user cannot see files in iTunes using a device older than 3.2 (the iPad), the NSLibraryDirectory constant has been available since iPhoneOS 2.0, and so can be used for builds targeting 3.0 (or even earlier if you are still doing that). Also the user will not be able to see anything unless you flag an app as allowing users to modify documents, so if you are using Documents today you are fine as long as you change location when updating for support of user documents.

Last there is a cache directory, where you can put images that you don't care exist for the long term or not (the phone may delete them at some point):

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [paths objectAtIndex:0];
BOOL isDir = NO;
NSError *error;
if (! [[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&isDir] && isDir == NO) {
    [[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:&error];
}

Note that you have to actually create the Caches directory there, so when writing you have to check and create every time! Kind of a pain, but that's how it is.

Then when you have a writable path, you just append a file name onto it like so:

NSString *filePath =  [documentsDirectory stringByAppendingPathComponent:@"SomeDirectory/SomeFile.txt"];

or

NSString *filePath =  [cachePath stringByAppendingPathComponent:@"SomeTmpFile.png"];

Use that path for reading or writing.

Note that you can make subdirectories in either of those writable paths, which one of the example string above is using (assuming one has been created).

If you are trying to write an image into the photo library, you cannot use file system calls to do this - instead, you have to have a UIImage in memory, and use the UIImageWriteToSavedPhotosAlbum() function call defined by UIKit. You have no control over the destination format or compression levels, and cannot attach any EXIF in this way.

Kendall Helmstetter Gelner
Don't build the path to Caches yourself. Use the same `NSSearchPathForDirectoriesInDomain()` function, but instead of using `NSDocumentDirectory`, use `NSCachesDirectory`.
Dave DeLong
Edited answer to use `NSCachesDirectory`
Dave DeLong
Thank you, good to know.
Kendall Helmstetter Gelner
http://idevkit.com/iphonedev/2009/09/saving-nsmutablearrays/there is a section in there on how to get the documents directory of your app, xcodeproj is included. It is based on saving an nsmutablearray and loading it again. It is essentially the same method for gettig the directory for saving other objects to.
Sj
That's nice but is tangental to the question, which is simply how to get an area you can write to. Plus the idea of StackOverflow is that this should act as the canonical repository of information.
Kendall Helmstetter Gelner