2016-05-09 12 views
3

Я использую UIDocumentPickerViewController, чтобы пользователь мог выбрать файл из iCloud Drive для загрузки на сервер.UIDocumentPickerViewController возвращает url в файл, который не существует

В большинстве случаев он работает правильно. Однако иногда (особенно, когда интернет-соединение является пятнистым) documentPicker:didPickDocumentAtURL: дает URL-адрес, который фактически не существует в файловой системе, и любая попытка его использования возвращает NSError «Нет такого файла или каталога».

Каков правильный способ справиться с этим? Я думаю об использовании NSFileManager fileExistsAtPath: и попросить пользователя повторить попытку, если он не существует. Но это не очень удобно. Есть ли способ получить реальную причину ошибки с iCloud Drive и, возможно, сообщить iCloud Drive, чтобы попробовать еще раз?

Соответствующие части кода:

@IBAction func add(sender: UIBarButtonItem) { 
    let documentMenu = UIDocumentMenuViewController(
     documentTypes: [kUTTypeImage as String], 
     inMode: .Import) 

    documentMenu.delegate = self 
    documentMenu.popoverPresentationController?.barButtonItem = sender 
    presentViewController(documentMenu, animated: true, completion: nil) 
} 

func documentMenu(documentMenu: UIDocumentMenuViewController, didPickDocumentPicker documentPicker: UIDocumentPickerViewController) { 
    documentPicker.delegate = self 
    documentPicker.popoverPresentationController?.sourceView = self.view 
    presentViewController(documentPicker, animated: true, completion: nil) 
} 

func documentPicker(controller: UIDocumentPickerViewController, didPickDocumentAtURL url: NSURL) { 
    print("original URL", url) 

    url.startAccessingSecurityScopedResource() 

    var error: NSError? 
    NSFileCoordinator().coordinateReadingItemAtURL(
    url, options: .ForUploading, error: &error) { url in 
     print("coordinated URL", url) 
    } 

    if let error = error { 
     print(error) 
    } 

    url.stopAccessingSecurityScopedResource() 
} 

Я воспроизведен путем добавления двух больших изображений (~ 5MiB каждое) ICloud Drive на OS X и открытие только один из них (a synced file.bmp) на iPhone и не открывая другое (an unsynced file.bmp). А затем отключил WiFi. Затем я попытался выбрать их в моем приложении:

синхронизированных файл:

original URL file:///private/var/mobile/Containers/Data/Application/CE70EE57-B906-4BF8-B351-A57110BE2B01/tmp/example.com.demo-Inbox/a%20synced%20file.bmp 
coordinated URL file:///private/var/mobile/Containers/Data/Application/CE70EE57-B906-4BF8-B351-A57110BE2B01/tmp/CoordinatedZipFileDR7e5I/a%20synced%20file.bmp 

без синхронизации файла:

original URL file:///private/var/mobile/Containers/Data/Application/CE70EE57-B906-4BF8-B351-A57110BE2B01/tmp/example.com.demo-Inbox/an%20unsynced%20file.bmp 
Error Domain=NSCocoaErrorDomain Code=260 "The file “an unsynced file.bmp” couldn’t be opened because there is no such file." UserInfo={NSURL=file:///private/var/mobile/Containers/Data/Application/CE70EE57-B906-4BF8-B351-A57110BE2B01/tmp/example.com.demo-Inbox/an%20unsynced%20file.bmp, NSFilePath=/private/var/mobile/Containers/Data/Application/CE70EE57-B906-4BF8-B351-A57110BE2B01/tmp/example.com.demo-Inbox/an unsynced file.bmp, NSUnderlyingError=0x15fee1210 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}} 
+0

У меня есть аналогичная проблема с импортом изображений с Google Диска с помощью UIDocumentPickerViewController. Возвращается верный URL, но fileExistsAtPath возвращает нуль (но только спорадически). Мне нужно использовать режим импорта (как и у вас), но я заметил, что проблема, кажется, исчезает, если я переключусь в режим Open. Кроме того, я считаю, что вам нужно только вызвать startAccessingSecurityScopedResource при использовании режима Open или Move. В моем тестировании этот вызов всегда возвращает false при использовании режима импорта. Сделали ли вы дальнейшие шаги по этому поводу после публикации? – grfryling

+0

@grfryling Я остановился на том, что дал пользователю сообщение об ошибке. Я попробовал Open mode, и я обнаружил, что могу использовать этот несуществующий url с [«вездесущими» функциями] (https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/index .html # // apple_ref/doc/uid/20000305-SW76), например 'startDownloadingUbiquitousItemAtURL: error:'. Однако я не использовал его, потому что Dropbox не поддерживает режим Open. – imgx64

ответ

1

У меня была такая же проблема, но оказалось, что я был вычеркивания Появилась директория Temp. Поэтому он будет сохранять, а затем удалять при появлении и правильном вызове documentPicker: didPickDocumentAtURL: только URL-адрес будет указывать на файл, который я удалил.

+0

Holy ... Я наткнулся на эту проблему в течение нескольких часов, и это было именно так! Визуальный контроллер в полностью отдельной части приложения выполняет очистку для каталога tmp на viewDidAppear, полностью убивая файлы из сборщика документов сразу после их создания. Совпадение, которое трудно отследить)) – IPv6

+0

Отлично, я был не единственным! Рад, что это помогло! – Jesper

1

Описание

Аналогичная проблема возникла у меня. У меня есть сборщика документ инициализирована как это:

var documentPicker: UIDocumentPickerViewController = UIDocumentPickerViewController(documentTypes: ["public.data"], in: .import) 

Это означает, что файлы копируются в каталог app_id-Inbox после того как они выбраны в documentPicker. Когда вызывается метод делегирования documentPicker(_:didPickDocumentsAt:), он дает URL-адреса, указывающие на файлы, которые находятся в каталоге app_id-Inbox.

Проблема

Через некоторое время (без закрытия приложения) эти URL-адреса указывали на файлы, которые не существующих. Это произошло потому, что app_id-Inbox в tmp/ папка была очищена тем временем. Например, я беру документы, показываю их в виде таблицы и оставляю iPhone на этом экране как минуту, а затем, когда я пытаюсь щелкнуть по конкретным документам, которые открывают файл в QLPreviewController, используя URL-адрес из documentPicker, он возвращает файл, который не существует.

Это похоже на ошибку, потому что документация состояние компании Apple следующего here

UIDocumentPickerModeImport

The URLs refer to a copy of the selected documents. These documents are temporary files. They remain available only until your application terminates. To keep a permanent copy, move these files to a permanent location inside your sandbox.

Это ясно говорит , пока приложение не завершит, но в моем случае, было около минуты, не открывая, что URL-адрес.

Обход

Переместить файлы из папки app_id-Inbox в tmp/ или любой другой директории, то использовать URL-адреса, которые указывают на новое место.

Swift 4

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { 
    let newUrls = urls.flatMap { (url: URL) -> URL? in 
     // Create file URL to temporary folder 
     var tempURL = URL(fileURLWithPath: NSTemporaryDirectory()) 
     // Apend filename (name+extension) to URL 
     tempURL.appendPathComponent(url.lastPathComponent) 
     do { 
      // If file with same name exists remove it (replace file with new one) 
      if FileManager.default.fileExists(atPath: tempURL.path) { 
       try FileManager.default.removeItem(atPath: tempURL.path) 
      } 
      // Move file from app_id-Inbox to tmp/filename 
      try FileManager.default.moveItem(atPath: url.path, toPath: tempURL.path) 
      return tempURL 
     } catch { 
      print(error.localizedDescription) 
      return nil 
     } 
    } 
    // ... do something with URLs 
} 

Хотя система будет заботиться о /tmp директории рекомендуется, чтобы очистить ее, когда он больше не нужен.

+0

Ницца, Это должно принять ответ. Спасибо. –