2013-04-25 20 views
28

Posso scaricare e salvare un file binario nella cartella 'Documenti' con un nome personalizzato perfettamente adatto.iOS: impossibile salvare il file nella cartella 'Application Support', ma può su 'Documents'

Se ho appena modificato l'URL nella cartella "Supporto applicazione" anziché nella cartella "Documenti", non riesce a scrivere su quell'URL dicendo che non esiste.

Ecco il codice di costruzione URL:

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

    if ([possibleURLs count] >= 1) 
    { 
     appSupportDir = [possibleURLs objectAtIndex:0]; 
    } 

    if (appSupportDir != nil) 
    { 
     NSString * appBundleID = [[NSBundle mainBundle] bundleIdentifier]; 
     appDirectory   = [appSupportDir URLByAppendingPathComponent:appBundleID]; 
    } 

    return appSupportDir; 
} 

Ecco il codice risparmio:

- (void) writeOutDataToFile:(NSData *)data 
{ 

    NSURL * finalURL = [self.rootPathURL URLByAppendingPathComponent:self.aFileName]; 

    [data writeToURL:finalURL atomically:YES]; 
} 

Se cambio la NSArray a:

NSArray * possibleURLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; 

allora salva bene .

Ho letto i documenti Apple su file e non riesco a risolvere il problema - cosa mi manca?

+0

Perché si aggiunge l'ID del gruppo alla fine del percorso? La directory è già unica per la tua app. L'aggiunta dell'id bundle è ridondante. – rmaddy

+0

Poiché tale codice viene copiato DIRETTAMENTE dalla Guida alla programmazione del file system Apple (Listato 2-1) come modo corretto di creare un URL per un elemento nella directory di supporto dell'app. – iOSProgrammingIsFun

+2

Questo codice non ha senso per iOS. Comunque va bene per OS X. In iOS, la directory 'Application Support' è già presente nella sandbox della tua app. In OS X, non lo è. – rmaddy

risposta

41

A differenza della directory , la directory Application Support non esiste nella sandbox dell'app per impostazione predefinita. Devi crearlo prima di poterlo usare.

e un modo molto più semplice per ottenere un riferimento alla directory è:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); 
NSString *appSupportDirectory = paths.firstObject; 
+0

Questo non funziona. Stesso errore: impossibile trovare/aprire il file. – iOSProgrammingIsFun

+7

Hai creato la directory come ho detto? – rmaddy

43

Nel caso qualcuno non è sicuro come fare ciò che rmaddy descrive:

NSString *appSupportDir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject]; 
//If there isn't an App Support Directory yet ... 
if (![[NSFileManager defaultManager] fileExistsAtPath:appSupportDir isDirectory:NULL]) { 
    NSError *error = nil; 
//Create one 
    if (![[NSFileManager defaultManager] createDirectoryAtPath:appSupportDir withIntermediateDirectories:YES attributes:nil error:&error]) { 
     NSLog(@"%@", error.localizedDescription); 
    } 
    else { 
// *** OPTIONAL *** Mark the directory as excluded from iCloud backups 
     NSURL *url = [NSURL fileURLWithPath:appSupportDir]; 
     if (![url setResourceValue:@YES 
          forKey:NSURLIsExcludedFromBackupKey 
          error:&error]) 
     { 
      NSLog(@"Error excluding %@ from backup %@", url.lastPathComponent, error.localizedDescription); 
     } 
     else { 
      NSLog(@"Yay"); 
     } 
    } 
} 
+1

Grazie per aver dedicato del tempo per condividere un esempio! – Doug

+0

@chrysallwood, cura di condividere la versione rapida? –

+0

Non ha funzionato per me, purtroppo – bgplaya

3

mi sono imbattuto lo stesso problema e ha deciso di utilizzare un approccio più concisa:

let fileManager = NSFileManager.defaultManager() 
let urls = fileManager.URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask) as! [NSURL] 
if let applicationSupportURL = urls.last { 
    fileManager.createDirectoryAtURL(applicationSupportURL, withIntermediateDirectories: true, attributes: nil, error: nil) 
} 

Questo funziona perché createDirectoryAtURL utilizzando withIntermediateDirectories: true crea la cartella solo se non esiste.

1

Ecco un codice Swift per iOS che può scrivere un file di dati binari nella directory di supporto dell'applicazione. Alcune parti di questo sono state ispirate dalla risposta di chrysAllwood.

/// Method to write a file containing binary data to the "application support" directory. 
    /// 
    /// - Parameters: 
    /// - fileName: Name of the file to be written. 
    /// - dataBytes: File contents as a byte array. 
    /// - optionalSubfolder: Subfolder to contain the file, in addition to the bundle ID subfolder. 
    ///      If this is omitted no extra subfolder is created/used. 
    /// - iCloudBackupForFolder: Specify false to opt out from iCloud backup for whole folder or 
    ///       subfolder. This is only relevant if this method call results in 
    ///       creation of the folder or subfolder, otherwise it is ignored. 
    /// - Returns: Nil if all OK, otherwise text for a couple of non-Error errors. 
    /// - Throws: Various errors possible, probably of type NSError. 
    public func writeBytesToApplicationSupportFile(_ fileName : String, 
                _ dataBytes : [UInt8], 
                optionalSubfolder : String? = nil, 
                iCloudBackupForFolder : Bool = true) 
               throws -> String? { 

     let fileManager = FileManager.default 

     // Get iOS directory for "application support" files 
     let appSupportDirectory = 
        fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first 
     if appSupportDirectory == nil { 
     return "Unable to determine iOS application support directory for this app." 
     } 

     // Add "bundle ID" as subfolder. This is recommended by Apple, although it is probably not 
     // necessary. 
     if Bundle.main.bundleIdentifier == nil { 
     return "Unable to determine bundle ID for the app." 
     } 
     var mySupportDirectory = 
        appSupportDirectory!.appendingPathComponent(Bundle.main.bundleIdentifier!) 

     // Add an additional subfolder if that option was specified 
     if optionalSubfolder != nil { 
     mySupportDirectory = appSupportDirectory!.appendingPathComponent(optionalSubfolder!) 
     } 

     // Create the folder and subfolder(s) as needed 
     if !fileManager.fileExists(atPath: mySupportDirectory.path) { 
     try fileManager.createDirectory(atPath: mySupportDirectory.path, 
             withIntermediateDirectories: true, attributes: nil) 

     // Opt out from iCloud backup for this subfolder if requested 
     if !iCloudBackupForFolder { 
      var resourceValues : URLResourceValues = URLResourceValues() 
      resourceValues.isExcludedFromBackup = true 
      try mySupportDirectory.setResourceValues(resourceValues) 
     } 
     } 

     // Create the file if necessary 
     let mySupportFile = mySupportDirectory.appendingPathComponent(fileName) 
     if !fileManager.fileExists(atPath: mySupportFile.path) { 
     if !fileManager.createFile(atPath: mySupportFile.path, contents: nil, attributes: nil) { 
      return "File creation failed." 
     } 
     } 

     // Write the file (finally) 
     let fileHandle = try FileHandle(forWritingTo: mySupportFile) 
     fileHandle.write(NSData(bytes: UnsafePointer(dataBytes), length: dataBytes.count) as Data) 
     fileHandle.closeFile() 

     return nil 
    }