ios - UIDocumentPickerViewController 将 url 返回到不存在的文件

标签 ios icloud icloud-drive uidocumentpickervc

我正在使用 UIDocumentPickerViewController让用户从 iCloud Drive 中选择一个文件上传到后端。

大多数时候,它都能正常工作。然而,有时(尤其是当互联网连接不稳定时)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()
}

我通过在 OS X 上的 iCloud Drive 中添加两个大图像(每个约 5MiB)并在 iPhone 上只打开其中一个(同步文件.bmp)而不打开另一个来重现这个(未同步的 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"}}

最佳答案

描述

我遇到了类似的问题。 我有这样初始化的文档选择器:

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

这意味着文件在documentPicker中被选中后被复制到app_id-Inbox目录。当调用委托(delegate)方法 documentPicker(_:didPickDocumentsAt:) 时,它会提供指向位于 app_id-Inbox 目录中的文件的 URL。

问题

一段时间后(没有关闭应用程序)这些 URL 指向不存在的文件。发生这种情况是因为同时清除了 tmp/ 文件夹中的 app_id-Inbox。例如,我选择文档,在表格 View 中显示它们并将 iPhone 留在该屏幕上大约一分钟,然后当我尝试单击特定文档时使用 提供的 URL 在 QLPreviewController 中打开文件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.compactMap { (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 目录,但建议在不再需要时清除其内容。

关于ios - UIDocumentPickerViewController 将 url 返回到不存在的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37109130/

相关文章:

ios - 如何从屏幕上删除行?

iphone - Objective-C 命名约定——澄清

ios - 用于上传和下载文件的 iCloud 集成

ios - 应用程序的 info.plist 中的 iCloud 显示集/NSUbiquitousDisplaySet

iphone - 手动同步 iCloud

ios - 具有自定义 UTI 的 iCloud 文档选取器

ios - 如何防止物体在场景包中转换阴影?

ios - 如何在 OS X 应用程序提供的 iOS8 上公开和检索 iCloud Drive 中的文件

ios - 如何在 iCloud Drive 上生成图像的缩略图?

ios - 我可以在大部分初始化和设置中使用 viewWillAppear 而不是 viewDidLoad 吗?