UIDocumentPickerViewController将url返回到不存在的文件 [英] UIDocumentPickerViewController returns url to a file that does not exist

查看:99
本文介绍了UIDocumentPickerViewController将url返回到不存在的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 UIDocumentPickerViewController ,以允许用户从iCloud驱动器中选择一个文件上传到后端.

I'm using UIDocumentPickerViewController to let the user select a file from iCloud Drive for uploading to the backend.

在大多数情况下,它可以正常工作.但是,有时(尤其是在互联网连接不连续的情况下)

Most of the time, it works correctly. However, sometimes (especially when the internet connection is spotty)documentPicker:didPickDocumentAtURL: gives a url that does not actually exist on the filesystem, and any attempt to use it returns a NSError "No such file or directory".

处理此问题的正确方法是什么?我正在考虑使用

What is the correct way to handle this? I'm thinking about using NSFileManager fileExistsAtPath: and tell the user to try again if it doesn't exist. But that doesn't sound very user friendly. Is there a way to get the real error reason from iCloud Drive and perhaps tell iCloud Drive to try again?

代码的相关部分:

@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上仅打开其中一个图像( asynced file.bmp )而不打开另一个图像来实现此目的(未同步的file.bmp ).然后关闭WiFi.然后,我尝试在应用程序中选择它们:

I reproduced this by adding two large images (~5MiB each) to iCloud Drive on OS X and opening only one of them (a synced file.bmp) on an iPhone and not opening the other (an unsynced file.bmp). And then turned off WiFi. Then I tried to select them in my application:

已同步的文件:

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

推荐答案

说明

类似的问题发生在我身上.我已经将文档选择器初始化为:

Description

Similar problem occurred to me. I have document picker initialized like this:

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

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

Which means that files are copied to app_id-Inbox directory after they are selected in documentPicker. When delegate method documentPicker(_:didPickDocumentsAt:) gets called it gives URLs which are pointing to files that are located in app_id-Inbox directory.

一段时间(不关闭应用程序)后,这些URL指向不存在的文件.发生这种情况是因为同时清除了 tmp/文件夹中的 app_id-Inbox .例如,我选择文档,以表格视图显示它们,然后将iPhone在屏幕上停留约一分钟,然后当我尝试单击特定文档时,使用从提供的URL在 QLPreviewController 中打开文件documentPicker 会返回不存在的文件.

After some time (without closing app) those URLs were pointing to files that are not existing. That happened because app_id-Inbox in tmp/ folder was cleared meanwhile. For example I pick documents, show them in table view and leave iPhone on that screen for like a minute, then when I try to click on specific documents which opens file in QLPreviewController using URL provided from documentPicker it returns file not existing.

这似乎是一个错误,因为Apple文档在此处

This seems like a bug because Apple's documentation states following here

UIDocumentPickerModeImport

UIDocumentPickerModeImport

URL是指所选文档的副本.这些文件是临时文件.它们仅在您的应用程序之前可用终止.要保留永久性副本,请将这些文件移至永久性沙箱中的位置.

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的大约一分钟.

It clearly says until application terminates, but in my case that was around minute of not opening that URL.

将文件从 app_id-Inbox 文件夹移动到 tmp/或任何其他目录,然后使用指向新位置的URL.

Move files from app_id-Inbox folder to tmp/ or any other directory then use URLs that are pointing to new location.

快捷键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 目录,但建议在不再需要它时清除其内容.


Although system will take care of /tmp directory it's recommended to clear its content when it's not needed anymore.

这篇关于UIDocumentPickerViewController将url返回到不存在的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆