135

Can someone explain to me what the documents directory is on an iOS app and when to use it?

Here is what I believe at present:

To me, it seems to be a central folder where the user can store any files needed for the app.

This would be a different location than where Core Data stores its data?

It seems like each app gets its own documents directory.

I am free to create a subdirectory of the documents directory, like documents directory/images, or documents directory/videos?

Pang
  • 9,564
  • 146
  • 81
  • 122
user798719
  • 9,619
  • 25
  • 84
  • 123
  • Iirc, the NSDocumentDirectory lie in the same path as the app core data, and each app has its own document directory. And yes, you can freely put whatever resources you need for your app here. By the way, it seems your question is not yet completed? – Zekareisoujin Aug 02 '11 at 04:52
  • I just posted something I think relates to your question in here http://stackoverflow.com/questions/5105250/run-nsbundle-from-the-documents-folder/7179584#7179584 check it to siee if it works for you. – Wytchkraft Aug 24 '11 at 17:20
  • For anyone coming from google, note that this has changed in iOS 8. See my answer below. – livingtech May 12 '15 at 20:42
  • its the same location where your sqlite file is saved. – Anurag Bhakuni Jun 09 '15 at 15:40

9 Answers9

202

Your app only (on a non-jailbroken device) runs in a "sandboxed" environment. This means that it can only access files and directories within its own contents. For example Documents and Library.

See the iOS Application Programming Guide.

To access the Documents directory of your applications sandbox, you can use the following:

iOS 8 and newer, this is the recommended method

+ (NSURL *)applicationDocumentsDirectory
{
     return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

if you need to support iOS 7 or earlier

+ (NSString *) applicationDocumentsDirectory 
{    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = paths.firstObject;
    return basePath;
}

This Documents directory allows you to store files and subdirectories your app creates or may need.

To access files in the Library directory of your apps sandbox use (in place of paths above):

[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]
ray
  • 1,966
  • 4
  • 24
  • 39
WrightsCS
  • 50,551
  • 22
  • 134
  • 186
  • 13
    I have discovered that [@"~/Documents" stringByExpandingTildeInPath] does the same thing. Is there any reason that this should be discouraged? – Cthutu May 23 '12 at 19:36
  • 36
    I wouldn't use the approach with @"~/Documents". Hardcoding paths is never a good idea. It may work now, but if Apple ever chooses to rename or move the Documents directory, your app will break. `NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);` will always give you the correct directory! –  Sep 21 '12 at 17:23
  • 16
    you should still use the provided API. That's why it's there! You've just been lucky until now. – nielsbot Jun 04 '13 at 22:50
  • 21
    Hilarious how I need to google this each time I have to use it. I think all mobile platforms should provide default global parameter for the home/writable directory – Ravindranath Akila Feb 18 '14 at 07:42
  • 1
    updated link with info on an app's ability to write to folders: https://developer.apple.com/library/mac/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW28 – phil Apr 23 '14 at 06:48
  • Make the `basePath` `static`, maybe? – Fahri Azimov Feb 23 '16 at 05:54
  • Thank you for the `iOS 7` version that is more like C++. Mentally translating from Objective-C is a pain. – Jesse Chisholm Oct 19 '17 at 01:10
  • I want to load image path from project folder in my Device can i do it using Document Directory – Khushbu Desai Jun 20 '18 at 08:34
44

This has changed in iOS 8. See the following tech note: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

The Apple sanctioned way (from the link above) is as follows:

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
livingtech
  • 3,570
  • 29
  • 42
  • 7
    **This is the answer you want!** The year is almost 2016 now. This is a popular question with out-dated answers. – Jeff Dec 06 '15 at 15:06
  • Can i use above method to retrieve the path of document directory? like url.path ? – Abuzar Amin Mar 07 '16 at 13:46
22

I couldn't find the code in the doc suggested by the accepted answer but I found the updated equivalent here:

File System Programming Guide :: Accessing Files and Directories »

- (NSURL*)applicationDataDirectory {
    NSFileManager* sharedFM = [NSFileManager defaultManager];
    NSArray* possibleURLs = [sharedFM URLsForDirectory:NSApplicationSupportDirectory
                                 inDomains:NSUserDomainMask];
    NSURL* appSupportDir = nil;
    NSURL* appDirectory = nil;

    if ([possibleURLs count] >= 1) {
        // Use the first directory (if multiple are returned)
        appSupportDir = [possibleURLs objectAtIndex:0];
    }

    // If a valid app support directory exists, add the
    // app's bundle ID to it to specify the final directory.
    if (appSupportDir) {
        NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
        appDirectory = [appSupportDir URLByAppendingPathComponent:appBundleID];
    }

    return appDirectory;
}

It discourages use of NSSearchPathForDirectoriesInDomain:

The NSSearchPathForDirectoriesInDomains function behaves like the URLsForDirectory:inDomains: method but returns the directory’s location as a string-based path. You should use the URLsForDirectory:inDomains: method instead.

Here are some other useful directory constants to play with. No doubt not all of these are supported in iOS. Also you can use the NSHomeDirectory() function which:

In iOS, the home directory is the application’s sandbox directory. In OS X, it is the application’s sandbox directory or the current user’s home directory (if the application is not in a sandbox)

From NSPathUtilities.h

NSApplicationDirectory = 1,             // supported applications (Applications)
    NSDemoApplicationDirectory,             // unsupported applications, demonstration versions (Demos)
    NSDeveloperApplicationDirectory,        // developer applications (Developer/Applications). DEPRECATED - there is no one single Developer directory.
    NSAdminApplicationDirectory,            // system and network administration applications (Administration)
    NSLibraryDirectory,                     // various documentation, support, and configuration files, resources (Library)
    NSDeveloperDirectory,                   // developer resources (Developer) DEPRECATED - there is no one single Developer directory.
    NSUserDirectory,                        // user home directories (Users)
    NSDocumentationDirectory,               // documentation (Documentation)
    NSDocumentDirectory,                    // documents (Documents)
    NSCoreServiceDirectory,                 // location of CoreServices directory (System/Library/CoreServices)
    NSAutosavedInformationDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 11,   // location of autosaved documents (Documents/Autosaved)
    NSDesktopDirectory = 12,                // location of user's desktop
    NSCachesDirectory = 13,                 // location of discardable cache files (Library/Caches)
    NSApplicationSupportDirectory = 14,     // location of application support files (plug-ins, etc) (Library/Application Support)
    NSDownloadsDirectory NS_ENUM_AVAILABLE(10_5, 2_0) = 15,              // location of the user's "Downloads" directory
    NSInputMethodsDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 16,           // input methods (Library/Input Methods)
    NSMoviesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 17,                 // location of user's Movies directory (~/Movies)
    NSMusicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 18,                  // location of user's Music directory (~/Music)
    NSPicturesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 19,               // location of user's Pictures directory (~/Pictures)
    NSPrinterDescriptionDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 20,     // location of system's PPDs directory (Library/Printers/PPDs)
    NSSharedPublicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 21,           // location of user's Public sharing directory (~/Public)
    NSPreferencePanesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 22,        // location of the PreferencePanes directory for use with System Preferences (Library/PreferencePanes)
    NSApplicationScriptsDirectory NS_ENUM_AVAILABLE(10_8, NA) = 23,      // location of the user scripts folder for the calling application (~/Library/Application Scripts/code-signing-id)
    NSItemReplacementDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 99,       // For use with NSFileManager's URLForDirectory:inDomain:appropriateForURL:create:error:
    NSAllApplicationsDirectory = 100,       // all directories where applications can occur
    NSAllLibrariesDirectory = 101,          // all directories where resources can occur
    NSTrashDirectory NS_ENUM_AVAILABLE(10_8, NA) = 102                   // location of Trash directory

And finally, some convenience methods in an NSURL category http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category

Hari Honor
  • 8,677
  • 8
  • 51
  • 54
8

Swift 3 and 4 as global var:

var documentsDirectory: URL {
    return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!
}

As FileManager extension:

extension FileManager {
    static var documentsDirectory: URL {
        return `default`.urls(for: .documentDirectory, in: .userDomainMask).last!
    }

    var documentsDirectory: URL {
        return urls(for: .documentDirectory, in: .userDomainMask).last!
    }
}
Anton Plebanovich
  • 1,296
  • 17
  • 17
  • Thanks. I always forget this. :) If you want to hold fast to API design guidelines, you could name it `documentDirectoryURL` or simply `documentDirectory` and rely on the type. I like the idea of scoping it to statically to `FileManager` though a static property in an extension. – Ray Fix Oct 23 '18 at 00:14
  • 1
    Thanks @RayFix, updated my answer with your suggestion! – Anton Plebanovich Oct 23 '18 at 12:36
6

Aside from the Documents folder, iOS also lets you save files to the temp and Library folders.

For more information on which one to use, see this link from the documentation:

Eric
  • 16,003
  • 15
  • 87
  • 139
6

It can be cleaner to add an extension to FileManager for this kind of awkward call, for tidiness if nothing else. Something like:

extension FileManager {
    static var documentDir : URL {
        return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    }
}
elasticrat
  • 7,060
  • 5
  • 36
  • 36
4

You can access documents directory using this code it is basically used for storing file in plist format:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
return documentsDirectory;
Keenle
  • 12,010
  • 3
  • 37
  • 46
Sumit Oberoi
  • 3,455
  • 2
  • 18
  • 18
  • This same answer was given 3 years prior by WrightsCS. Also, giving this answer in 2014 is odd considering Apple recommends the method in livingtech's answer. – Jeff Dec 06 '15 at 15:14
  • If you think I am wrong to down vote, then please explain why. A revenge down vote on one of my questions is childish. This site it about pushing the best answers to the top. – Jeff Dec 10 '15 at 14:38
  • @jeff thank you for pointing out, did some research and you were right. new solution : - (NSURL *)applicationDocumentsDirectory { return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; } – Sumit Oberoi Dec 16 '15 at 10:00
1

Here's a useful little function, which makes using/creating iOS folders a little easier.

You pass it the name of a subfolder, it'll return the full path back to you, and make sure the directory exists.

(Personally, I stick this static function in my AppDelete class, but perhaps this isn't the smartest place to put it.)

Here's how you would call it, to get the "full path" of a MySavedImages subdirectory:

NSString* fullPath = [AppDelegate getFullPath:@"MySavedImages"];

And here's the full function:

+(NSString*)getFullPath:(NSString*)folderName
{
    //  Check whether a subdirectory exists in our sandboxed Documents directory.
    //  Returns the full path of the directory.
    //
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    if (paths.count < 1)
        return nil;

    NSString *rootFolder = [paths firstObject];
    NSString* fullFolderPath = [rootFolder stringByAppendingPathComponent:folderName];

    BOOL isDirectory;
    NSFileManager* manager = [NSFileManager defaultManager];

    if (![manager fileExistsAtPath:fullFolderPath isDirectory:&isDirectory] || !isDirectory) {
        NSError *error = nil;
        NSDictionary *attr = [NSDictionary dictionaryWithObject:NSFileProtectionComplete
                                                         forKey:NSFileProtectionKey];
        [manager createDirectoryAtPath:fullFolderPath
           withIntermediateDirectories:YES
                            attributes:attr
                                 error:&error];
        if (error) {
            NSLog(@"Error creating directory path: %@", [error localizedDescription]);
            return nil;
        }
    }
    return fullFolderPath;
}

Using this little function, it's easy to create a directory in your app's Documents directory (if it doesn't already exist), and to write a file into it.

Here's how I would create the directory, and write the contents of one of my image files into it:

//  Let's create a "MySavedImages" subdirectory (if it doesn't already exist)
NSString* fullPath = [AppDelegate getFullPath:@"MySavedImages"];

//  As an example, let's load the data in one of my images files
NSString* imageFilename = @"icnCross.png";

UIImage* image = [UIImage imageNamed:imageFilename];
NSData *imageData = UIImagePNGRepresentation(image);

//  Obtain the full path+filename where we can write this .png to, in our new MySavedImages directory
NSString* imageFilePathname = [fullPath stringByAppendingPathComponent:imageFilename];

//  Write the data
[imageData writeToFile:imageFilePathname atomically:YES];

Hope this helps !

Mike Gledhill
  • 27,846
  • 7
  • 149
  • 159
0

Like others mentioned, your app runs in a sandboxed environment and you can use the documents directory to store images or other assets your app may use, eg. downloading offline-d files as user prefers - File System Basics - Apple Documentation - Which directory to use, for storing application specific files

Updated to swift 5, you can use one of these functions, as per requirement -

func getDocumentsDirectory() -> URL {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return paths[0]
}

func getCacheDirectory() -> URL {
        let paths = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
        return paths[0]
    }

func getApplicationSupportDirectory() -> URL {
        let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
        return paths[0]
    }

Usage:

let urlPath = "https://jumpcloud.com/wp-content/uploads/2017/06/SSH-Keys.png" //Or string path to some URL of valid image, for eg.

if let url = URL(string: urlPath){
    let destination = getDocumentsDirectory().appendingPathComponent(url.lastPathComponent)
    do {
        let data = try Data(contentsOf: url) //Synchronous call, just as an example
        try data.write(to: destination)
    } catch _ {
        //Do something to handle the error
    }
}
akashlal.com
  • 356
  • 2
  • 12