Подтвердить что ты не робот

IOS: не удается сохранить файл в папке "Поддержка приложений", но может быть в "Документах",

Я могу загрузить и сохранить двоичный файл в папке "Документы" с настраиваемым именем отлично.

Если я просто изменил URL-адрес в папку "Поддержка приложений" вместо папки "Документы", он не сможет записать на этот URL-адрес, что его не существует.

Здесь код построения 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;
}

Здесь сохраненный код:

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

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

    [data writeToURL:finalURL atomically:YES];
}

Если я изменил NSArray на:

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

тогда он сохраняет штраф.

Я читал файлы Apple Docs on File и не могу исправить это - что мне не хватает?

4b9b3361

Ответ 1

В отличие от каталога Documents каталог Application Support по умолчанию не существует в песочнице приложений. Вам нужно создать его, прежде чем вы сможете его использовать.

И гораздо более простой способ получить ссылку на каталог:

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

Ответ 2

Если кто-то не знает, как это сделать, что описывает rmaddy:

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");
        }
    }
}

Ответ 3

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

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)
}

Это работает, потому что createDirectoryAtURL с помощью withIntermediateDirectories: true создает папку только в том случае, если она не существует.

Ответ 4

Здесь приведен код Swift для iOS, который может записать файл двоичных данных в каталог поддержки приложения. Части этого были вдохновлены ответом 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
   }

Ответ 5

Один лайнер - создаст при необходимости тоже:

[[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil]

Ответ 6

Версия Swift 4.2

    let fileManager = FileManager.default
    let urls = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask)
    if let applicationSupportURL = urls.last {
        do{
            try fileManager.createDirectory(at: applicationSupportURL, withIntermediateDirectories: true, attributes: nil)
        }
        catch{
            print(error)
        }
    }