2016-05-09 25 views
3

Ich verwende UIDocumentPickerViewController, damit der Benutzer eine Datei von iCloud Drive zum Hochladen auf das Backend auswählen kann.UIDocumentPickerViewController gibt URL zu einer Datei zurück, die nicht existiert

Die meiste Zeit funktioniert es richtig. Jedoch manchmal (vor allem wenn die Internetverbindung ist fleckig) documentPicker:didPickDocumentAtURL: gibt eine URL, die nicht tatsächlich auf dem Dateisystem vorhanden ist, und jeder Versuch, es zu verwenden gibt einen NSError "Keine solche Datei oder Verzeichnis".

Was ist der richtige Weg, damit umzugehen? Ich denke über die Verwendung von NSFileManager fileExistsAtPath: und sagen Sie dem Benutzer, es erneut zu versuchen, wenn es nicht existiert. Aber das klingt nicht sehr benutzerfreundlich. Gibt es eine Möglichkeit, den tatsächlichen Fehlergrund von iCloud Drive zu erhalten und iCloud Drive möglicherweise zu versuchen, es erneut zu versuchen?

Die relevanten Teile des Codes:

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

ich dies, indem zwei große Bilder (~ 5MiB jeweils) zu iCloud-Laufwerk auf OS X und Öffnung nur einer von ihnen (a synced file.bmp) auf einem iPhone wiedergegeben und den anderen nicht öffnen (an unsynced file.bmp). Und dann WiFi ausgeschaltet. Dann habe ich versucht, sie in meiner Anwendung zu wählen:

Die synchronisierten Datei:

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 

Die nicht synchronisierten Datei:

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

Ich habe ein ähnliches Problem beim Importieren von Bildern aus Google Drive mit UIDocumentPickerViewController. Eine gültige URL wird zurückgegeben, aber fileExistsAtPath gibt nil (aber nur sporadisch) zurück. Ich muss den Import-Modus verwenden (wie Sie haben), aber ich habe festgestellt, dass das Problem scheint wegzugehen, wenn ich in den offenen Modus wechseln. Außerdem glaube ich, dass Sie nur startAccessingSecurityScopedResource aufrufen müssen, wenn Sie den Open- oder Move-Modus verwenden. In meinen Tests gibt dieser Aufruf immer den Wert false zurück, wenn der Importmodus verwendet wird. Haben Sie seit dem Entsenden weitere Fortschritte gemacht? – grfryling

+0

@grfryling Ich entschied mich für eine vage Fehlermeldung an den Benutzer. Ich habe den Open-Modus ausprobiert und festgestellt, dass ich diese nicht existierende URL mit ["allgegenwärtigen" Funktionen] (https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/index) verwenden könnte .html # // apple_ref/doc/uid/20000305-SW76) wie 'startDownloadingUbiquitousItemAtURL: error:'. Ich habe es jedoch nicht verwendet, da Dropbox den Open-Modus nicht unterstützt. – imgx64

Antwort

1

hatte ich das gleiche Problem, aber es stellte sich heraus, dass ich das Löschen der Das Temp-Verzeichnis in der Ansicht wurde angezeigt. So würde es speichern, dann löschen, wenn Sie erscheinen und ordnungsgemäß aufrufen documentPicker: didPickDocumentAtURL: nur URL würde auf die Datei zeigen, die ich gelöscht hatte.

+0

Holy ... Ich stolperte mehrere Stunden lang über dieses Problem und das war genau der Fall! Visueller Controller im vollständig separaten Teil der Anwendung führt das Verzeichnis clean for tmp in viewDidAppear aus und löscht Dateien direkt nach der Erstellung vollständig aus der Dokumentauswahl. Zufall, das ist schwer aufzuspüren)) – IPv6

+0

Toll war ich nicht der Einzige! Froh, dass es geholfen hat! – Jesper

1

Beschreibung

Ähnliche Probleme traten auf. I Dokument Picker wie folgt initialisiert haben:

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

was bedeutet, dass Dateien in app_id-Inbox Verzeichnis kopiert werden, nachdem sie in documentPicker ausgewählt sind. Wenn die Delegate-Methode documentPicker(_:didPickDocumentsAt:) aufgerufen wird, werden URLs angegeben, die auf Dateien verweisen, die sich im Verzeichnis app_id-Inbox befinden.

Problem

Nach einiger Zeit (ohne App Schließen) diese URLs wurden auf Dateien, die nicht existieren. Das passierte, weil app_id-Inbox in tmp/ Ordner inzwischen gelöscht wurde. Zum Beispiel wähle ich Dokumente aus, zeige sie in der Tabellenansicht an und lasse das iPhone für eine Minute auf dem Bildschirm. Wenn ich dann auf bestimmte Dokumente klicke, öffnet sich die Datei in QLPreviewController unter Verwendung der URL documentPicker. Die Datei wird nicht zurückgegeben.

Dies scheint ein Fehler, weil Apples Dokumentation wird folgende 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.

Er sagt klar bis zur Anwendung beendet, aber in meinem Fall, die sich um Minute war nicht, dass die URL zu öffnen.

Umgehung

Verschieben von Dateien von app_id-Inbox Ordnern tmp/ oder einem anderen Verzeichnis dann URLs verwenden, der neue Position zeigen werden.

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 
} 

Obwohl Systempflege von /tmp Verzeichnis nehmen wird es empfohlen wird seinen Inhalt zu löschen, wenn es nicht mehr gebraucht wird.

+0

Schön, das sollte Antwort akzeptieren. Vielen Dank. –