Come posso ottenere un percorso scrivibile su iPhone?

Sto postando questa domanda perché ho avuto una risposta completa per questo scritto per un altro post, quando ho trovato che non si applicava all’originale ma pensavo che fosse troppo utile per sprecare. Così ho anche reso questo un wiki della comunità, in modo che altri possano dare una risposta alle domande e alle risposte. Se trovi la risposta utile, vota per favore la domanda: essendo una wiki della comunità, non dovrei ottenere punti per questo voto, ma aiuterà gli altri a trovarlo

Come posso ottenere un percorso in cui sono consentite le scritture di file su iPhone? Puoi (in modo fuorviante) scrivere ovunque sul simulatore, ma su iPhone ti è permesso solo di scrivere in posizioni specifiche.

Esistono tre tipi di percorsi scrivibili da considerare: il primo è Documenti, in cui si archiviano le cose che si desidera conservare e rendere disponibili all’utente tramite iTunes (a partire da 3.2):

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

In secondo luogo, e molto simile alla directory Documenti, c’è la cartella Libreria, in cui si archiviano i file di configurazione e i database scrivibili che si desidera mantenere, ma non si vuole che l’utente sia in grado di fare confusione con iTunes:

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

Nota che anche se l’utente non può vedere i file in iTunes usando un dispositivo più vecchio di 3,2 (l’iPad), la costante NSLibraryDirectory è disponibile da iPhoneOS 2.0, e quindi può essere usata per il targeting di build 3.0 (o anche prima se stai ancora facendo quella). Inoltre, l’utente non sarà in grado di vedere nulla a meno che non si contrassegna un’app che consenta agli utenti di modificare i documenti, quindi se si sta utilizzando Documenti oggi si ha la certezza di cambiare posizione durante l’aggiornamento per il supporto dei documenti dell’utente.

Infine c’è una directory della cache, dove puoi mettere immagini a cui non t’interessa a lungo termine o meno (il telefono potrebbe cancellarle ad un certo punto):

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

Nota che devi effettivamente creare la directory Caches lì, quindi quando scrivi devi controllare e creare ogni volta! Una specie di dolore, ma è così.

Quindi quando hai un percorso scrivibile, devi semplicemente aggiungere un nome al file in questo modo:

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

o

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

Usa quel percorso per leggere o scrivere.

Si noti che è ansible creare sottodirectory in uno di questi percorsi scrivibili, che utilizza una delle stringhe di esempio sopra riportate (supponendo che ne sia stata creata una).

Se si sta tentando di scrivere un’immagine nella libreria di foto, non è ansible utilizzare le chiamate del sistema file per farlo – invece, è necessario avere una memoria UII in memoria e utilizzare la chiamata della funzione UIImageWriteToSavedPhotosAlbum() definita da UIKit. Non hai il controllo sul formato di destinazione o sui livelli di compressione e non puoi albind EXIF ​​in questo modo.

Grazie a Kendall e Dave, sopra, e ho pensato che questo emendamento fosse utile da illustrare. Usando un codice di debug one-off, ho usato questo trucco da NSBlog di Mike Ash per eliminare le variabili temporanee isDir & error, riducendo al minimo il numero di righe e rendendo la verbosità quasi sopportabile:

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