Wie kann ich einen beschreibbaren Pfad auf dem iPhone erhalten?

72

Ich poste diese Frage, weil ich eine vollständige Antwort auf diese Frage für einen anderen Beitrag hatte, als ich feststellte, dass sie nicht für das Original gilt, aber ich dachte, sie wäre zu nützlich, um sie zu verschwenden. Daher habe ich dies auch zu einem Community-Wiki gemacht, damit andere Fragen und Antworten ausarbeiten können. Wenn Sie die Antwort nützlich finden, stimmen Sie bitte über die Frage ab. Als Community-Wiki sollte ich keine Punkte für diese Abstimmung erhalten, aber es wird anderen helfen, sie zu finden

Wie kann ich einen Pfad ermitteln, in den das Schreiben von Dateien auf dem iPhone zulässig ist? Sie können (irreführend) im Simulator schreiben, wo immer Sie möchten, aber auf dem iPhone dürfen Sie nur an bestimmten Stellen schreiben.

Kendall Helmstetter Gelner
quelle

Antworten:

185

Es gibt drei Arten von beschreibbaren Pfaden: Der erste ist "Dokumente", in denen Sie Dinge speichern, die Sie behalten und dem Benutzer über iTunes (ab Version 3.2) zur Verfügung stellen möchten:

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

Zweitens, und dem Verzeichnis "Dokumente" sehr ähnlich, gibt es den Ordner "Bibliothek", in dem Sie Konfigurationsdateien und beschreibbare Datenbanken speichern, die Sie ebenfalls behalten möchten, mit denen der Benutzer jedoch nicht über iTunes herumspielen kann:

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

Beachten Sie, dass die NSLibraryDirectory-Konstante seit iPhoneOS 2.0 verfügbar ist, obwohl der Benutzer Dateien in iTunes mit einem Gerät, das älter als 3.2 (iPad) ist, nicht sehen kann. Sie kann daher für Builds verwendet werden, die auf 3.0 abzielen (oder sogar früher, wenn Sie dies noch tun) Das). Außerdem kann der Benutzer nichts sehen, es sei denn, Sie kennzeichnen eine App so, dass Benutzer Dokumente ändern können. Wenn Sie also heute Dokumente verwenden, ist dies in Ordnung, solange Sie beim Aktualisieren den Speicherort ändern, um Benutzerdokumente zu unterstützen.

Zuletzt gibt es ein Cache-Verzeichnis, in das Sie Bilder einfügen können, die Ihnen langfristig egal sind oder nicht (das Telefon kann sie irgendwann löschen):

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

Beachten Sie, dass Sie das Caches-Verzeichnis dort tatsächlich erstellen müssen. Wenn Sie also schreiben, müssen Sie jedes Mal überprüfen und erstellen! Eine Art Schmerz, aber so ist es.

Wenn Sie dann einen beschreibbaren Pfad haben, fügen Sie einfach einen Dateinamen wie folgt hinzu:

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

oder

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

Verwenden Sie diesen Pfad zum Lesen oder Schreiben.

Beachten Sie, dass Sie Unterverzeichnisse in einem dieser beschreibbaren Pfade erstellen können, die in einer der obigen Beispielzeichenfolgen verwendet werden (vorausgesetzt, eines wurde erstellt).

Wenn Sie versuchen, ein Bild in die Fotobibliothek zu schreiben, können Sie dazu keine Dateisystemaufrufe verwenden. Stattdessen müssen Sie ein UIImage im Speicher haben und den UIImageWriteToSavedPhotosAlbum()von UIKit definierten Funktionsaufruf verwenden. Sie haben keine Kontrolle über das Zielformat oder die Komprimierungsstufen und können auf diese Weise kein EXIF ​​anhängen.

Kendall Helmstetter Gelner
quelle
6
Bauen Sie den Pfad zu Caches nicht selbst auf. Verwenden Sie dieselbe NSSearchPathForDirectoriesInDomain()Funktion, aber anstatt sie zu verwenden NSDocumentDirectory, verwenden Sie NSCachesDirectory.
Dave DeLong
Bearbeitete Antwort zu verwendenNSCachesDirectory
Dave DeLong
idevkit.com/iphonedev/2009/09/saving-nsmutablearrays Dort finden Sie einen Abschnitt darüber, wie Sie das Dokumentenverzeichnis Ihrer App abrufen können. xcodeproj ist enthalten. Es basiert auf dem Speichern und erneuten Laden eines nsmutablearray. Es ist im Wesentlichen dieselbe Methode, um das Verzeichnis zum Speichern anderer Objekte abzurufen.
Sj.
2
Das ist schön, aber tangential zur Frage, wie man einfach einen Bereich bekommt, in den man schreiben kann. Die Idee von StackOverflow ist außerdem, dass dies als kanonisches Informationsarchiv fungieren soll.
Kendall Helmstetter Gelner
Laut: [Programmierhandbuch für iOS-Anwendungen] ( developer.apple.com/library/ios/#documentation/iPhone/… ) ist NSLibraryDirectory kein empfohlener Pfad, stattdessen schlägt Apple das NSApplicationSupportDirectory vor. Vielleicht sollte das Wiki aktualisiert werden, um dies widerzuspiegeln?
Hwaxxer
5

Vielen Dank an Kendall & Dave oben, und ich fand diesen Änderungsantrag nützlich, um ihn zur Sprache zu bringen. Bei der Verwendung für einmaligen Debug-Code habe ich diesen Trick aus Mike Ashs NSBlog verwendet , um die temporären Variablen isDir & error zu entfernen, die Anzahl der Zeilen zu minimieren und die Ausführlichkeit fast erträglich zu machen:

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];
Pierre Houston
quelle