Как я могу получить доступный для записи путь на iPhone?

Я отправляю этот вопрос, потому что у меня был полный ответ на это, написанный для другого сообщения, когда я обнаружил, что это не относится к оригиналу, но я думал, что он слишком полезен для того, чтобы тратить время. Таким образом, я также сделал это сообщество wiki, чтобы другие могли задавать вопросы и отвечать. Если вы найдете ответ полезным, пожалуйста, проголосуйте за вопрос - быть вики-сообществом, я не должен получать баллы за это голосование, но это поможет другим найти его

Как я могу получить путь, на который можно записывать файлы на iPhone? Вы можете (вводящим в заблуждение) писать в любом месте, где хотите, на Симуляторе, но на iPhone вам разрешено писать только в определенных местах.

Ответ 1

Существует три типа путей для записи: первый - это документы, в которых вы храните вещи, которые хотите сохранить, и предоставляете пользователю через iTunes (начиная с 3.2):

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

Во-вторых, и очень похожая на папку "Документы", есть папка "Библиотека", в которой хранятся файлы конфигурации и записываемые базы данных, которые вы также хотите сохранить, но вы не хотите, чтобы пользователь мог взаимодействовать через Itunes:

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

Обратите внимание, что даже если пользователь не может видеть файлы в iTunes с помощью устройства старше 3.2 (iPad), константа NSLibraryDirectory доступна с iPhoneOS 2.0 и поэтому может использоваться для создания таргетинга 3.0 (или даже раньше, если вы все еще делают это). Кроме того, пользователь не сможет ничего увидеть, если вы не отметите приложение как позволяющее пользователям изменять документы, поэтому, если вы используете Документы сегодня, вы в порядке, пока вы меняете место при обновлении для поддержки пользовательских документов.

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

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];
}

Обратите внимание, что вам действительно нужно создать каталог Caches, поэтому при записи вам нужно каждый раз проверять и создавать! Вид боли, но как это.

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

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

или

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

Используйте этот путь для чтения или записи.

Обратите внимание, что вы можете создавать поддиректории на любом из путей, доступных для записи, который используется в одной из приведенных выше примерной строки (при условии, что она была создана).

Если вы пытаетесь записать изображение в библиотеку фотографий, вы не можете использовать вызовы файловой системы для этого - вместо этого вы должны иметь UIImage в памяти и использовать вызов функции UIImageWriteToSavedPhotosAlbum(), определенный UIKit. Вы не контролируете формат адресата или уровень сжатия и не можете прикреплять EXIF ​​таким образом.

Ответ 2

Благодаря Кендалл и Дейву, выше, и я думал, что эта поправка была полезной для воспитания. При использовании для одноразового кода отладки я использовал этот трюк от Mike Ash NSBlog, чтобы исключить временные переменные isDir и ошибку, минимизируя количество строк и делая многословие почти приемлемым:

NSFileHandle *dumpFileHandle = nil;
#ifdef DEBUG
    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    if (![[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&(BOOL){0}])
        [[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:&(NSError*){nil}];
    NSString *dumpPath = [cachePath stringByAppendingPathComponent:@"dump.txt"];
    [[NSFileManager defaultManager] createFileAtPath:dumpPath contents:nil attributes:nil];
    [(dumpFileHandle = [NSFileHandle fileHandleForWritingAtPath:dumpPath]) truncateFileAtOffset:0];
#endif

if (dumpFileHandle) [dumpFileHandle writeData:blah];