img*_*x64 9 ios icloud uidocumentpickervc icloud-drive
我UIDocumentPickerViewController用来让用户从iCloud Drive中选择一个文件上传到后端.
大多数时候,它工作正常.但是,有时(特别是当互联网连接不稳定时)documentPicker:didPickDocumentAtURL:会给出一个文件系统上实际不存在的URL,并且任何使用它的尝试都会返回NSError"No such file or directory".
处理这个问题的正确方法是什么?我正在考虑使用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()
}
Run Code Online (Sandbox Code Playgroud)
我通过在OS X上向iCloud Drive添加两个大图像(每个~5MiB)并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
Run Code Online (Sandbox Code Playgroud)
未同步的文件:
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"}}
Run Code Online (Sandbox Code Playgroud)
Naj*_*mić 21
类似的问题发生在我身上.我有文件选择器初始化如下:
var documentPicker: UIDocumentPickerViewController = UIDocumentPickerViewController(documentTypes: ["public.data"], in: .import)
Run Code Online (Sandbox Code Playgroud)
这意味着文件app_id-Inbox在被选中后会被复制到目录中documentPicker.当委托方法documentPicker(_:didPickDocumentsAt:)被调用时,它会提供指向位于app_id-Inbox目录中的文件的URL .
一段时间后(没有关闭应用程序)这些URL指向不存在的文件.发生这种情况是因为同时清除app_id-Inbox了tmp/文件夹.例如,我选择文档,在表格视图中显示它们并将iPhone保留在该屏幕上一分钟,然后当我尝试单击打开文件的特定文档时,QLPreviewController使用documentPicker它提供的URL 返回文件不存在.
这似乎是一个错误,因为Apple的文档在此处说明
UIDocumentPickerModeImport
URL指的是所选文档的副本.这些文件是临时文件.它们仅在您的应用程序终止之前保持可用.要保留永久副本,请将这些文件移动到沙箱中的永久位置.
它明确说明直到应用程序终止,但在我的情况下,大约是没有打开该URL.
将文件从app_id-Inbox文件夹移动到tmp/任何其他目录,然后使用指向新位置的URL.
斯威夫特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
}
Run Code Online (Sandbox Code Playgroud)
虽然系统会处理/tmp目录,但建议在不再需要时清除其内容.
小智 6
我不认为问题在于以某种方式清理了 tmp 目录。
如果您使用模拟器并从 icloud 打开文件,您将看到该文件存在于 app-id-Inbox 中,并且未清除/删除。因此,当您尝试读取文件或复制并执行文件不存在的错误时,我认为这是一个安全问题,因为您可以看到该文件仍然存在。
在 DocumentPickerViewController 的导入模式下,我用这个解决了它(对不起,我将粘贴 c# 代码而不是 swift 因为我有它在我面前)
在 DidPickDocument 方法中返回我所做的 NSUrl
NSData fileData = NSData.FromUrl(url);
Run Code Online (Sandbox Code Playgroud)
现在您拥有包含文件数据的“fileData”变量。
然后您可以将它们复制到应用程序隔离空间中的自定义文件夹中,并且效果很好。
小智 5
使用文档选择器时,为了使用文件系统,请将 url 转换为文件路径,如下所示:
var filePath = urls[0].absoluteString
filePath = filePath.replacingOccurrences(of: "file:/", with: "")//making url to file path
Run Code Online (Sandbox Code Playgroud)
小智 1
我遇到了同样的问题,但事实证明我正在删除视图上的 Temp 目录,确实出现了。因此,它会在出现时保存然后删除,并正确调用 documentPicker:didPickDocumentAtURL: only url 会指向我已删除的文件。