Что такое каталог документов (NSDocumentDirectory)?

Может кто-нибудь объяснить мне, что каталог документов находится в приложении iOS и когда его использовать?

Вот что я считаю в настоящее время:

Мне кажется, что это центральная папка, где пользователь может хранить любые файлы, необходимые для приложения.

Это будет другое место, чем где Core Data хранит свои данные?

Кажется, что каждое приложение получает свой собственный каталог документов.

Я могу создать подкаталог каталога документов, например каталог/изображения документов или каталог документов/видео?

Ответ 1

Только ваше приложение (на устройстве без взлома) работает в среде с песочницей. Это означает, что он может обращаться к файлам и каталогам только в пределах собственного содержимого. Например Документы и Библиотека.

Смотрите Руководство по программированию приложений iOS.

Чтобы получить доступ к папке Документы изолированной программной среды приложений, вы можете использовать следующее:

iOS 8 и новее, это рекомендуемый метод

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

, если вам нужно поддерживать iOS 7 или ранее

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

Этот каталог Документы позволяет хранить файлы и подкаталоги, созданные или требуемые вашим приложением.

Чтобы получить доступ к файлам в папке Библиотека для использования в песочнице ваших приложений (вместо paths выше):

[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]

Ответ 2

Это изменилось в iOS 8. См. следующее техническое примечание: https://developer.apple.com/library/ios/technotes/tn2406/_index.html

Способ применения Apple (по ссылке выше) выглядит следующим образом:

// Returns the URL to the application Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

Ответ 3

Я не смог найти код в документе, предложенный принятым ответом, но я нашел обновленный эквивалент здесь:

Руководство по программированию файловой системы:: Доступ к файлам и каталогам

- (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 bundle ID to it to specify the final directory.
    if (appSupportDir) {
        NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
        appDirectory = [appSupportDir URLByAppendingPathComponent:appBundleID];
    }

    return appDirectory;
}

Это препятствует использованию NSSearchPathForDirectoriesInDomain:

Функция NSSearchPathForDirectoriesInDomains ведет себя как URLsForDirectory: inDomains: метод, но возвращает каталоги местоположение в виде строкового пути. Вы должны использовать URLsForDirectory: inDomains: вместо этого.

Вот некоторые другие полезные константы каталогов. Несомненно, не все из них поддерживаются в iOS. Также вы можете использовать функцию NSHomeDirectory(), которая:

В iOS домашний каталог представляет собой изолированную папку приложений. В OS X это папка с песочниц приложений или текущий домашний каталог пользователей (если приложение не находится в изолированной программной среде)

Из 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 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 "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 Movies directory (~/Movies)
    NSMusicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 18,                  // location of user Music directory (~/Music)
    NSPicturesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 19,               // location of user Pictures directory (~/Pictures)
    NSPrinterDescriptionDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 20,     // location of system PPDs directory (Library/Printers/PPDs)
    NSSharedPublicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 21,           // location of user 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 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

И, наконец, некоторые удобные методы в категории NSURL http://club15cc.com/code/ios/easy-ios-file-directory-paths-with-this-handy-nsurl-category

Ответ 4

Этот код работает для меня в Swift 2.1

func getDocsDir() -> NSURL? {
    let fm = NSFileManager.defaultManager()
    return fm.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last
}

Ответ 5

Swift 3 и 4 как глобальный var:

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

Ответ 6

Помимо папки Documents, iOS также позволяет сохранять файлы в папках temp и Library.

Для получения дополнительной информации о том, какой из них использовать, см. эту ссылку в документации:

Ответ 7

Вы можете обращаться к каталогу документов, используя этот код, который в основном используется для хранения файла в формате plist:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
return documentsDirectory;

Ответ 8

Здесь полезная небольшая функция, которая упрощает использование/создание папок iOS.

Вы передаете ему имя подпапки, оно вернет вам полный путь и убедитесь, что каталог существует.

(Лично я придерживаюсь этой статической функции в классе AppDelete, но, возможно, это не самое умное место для ее размещения.)

Здесь вы бы назвали его, чтобы получить "полный путь" в подкаталоге MySavedImages:

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

И здесь полная функция:

+(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;
}

Используя эту небольшую функцию, легко создать каталог в каталоге документов приложения (если он еще не существует) и записать в него файл.

Вот как бы я создал каталог и записал в него содержимое одного из моих файлов изображений:

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

//  As an example, let 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];

Надеюсь, это поможет!

Ответ 9

Это может быть чище добавлять расширение к FileManager для такого рода неудобного вызова, для аккуратности, если ничего другого. Что-то вроде:

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