除了打开并保存自己的自定义文档外,我的iOS 11基于文档浏览器的应用程序应该能够导入格式正确的文本文件并将其转换为自己的文档。
但是,在文档浏览器中选择文本文件时,只有当所选文件位于本地存储中时,应用才能访问其内容(然后执行转换),但无法访问内容时该文件存储在iCloud 。
下面提供了我用于documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL])
委托方法的代码的简化注释版本:
func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) {
guard let sourceURL = documentURLs.first else { return }
// Check extension to verify if it is a custom document
if sourceURL.pathExtension == "mydoc" {
// If it is a custom document, we present it directly
// (the presentDocument method is a standard implementation from Apple docs)
presentDocument(at: sourceURL)
} else {
// Otherwise, we suppose the file is a text file to be imported
// We first create a new document, then try to import the contents of the text file
let url = FileManager().temporaryDirectory.appendingPathComponent("New Document").appendingPathExtension("mydoc")
let doc = MyDocument(fileURL: url)
do {
let textFileContents = try String(contentsOf: sourceURL)
// It works fine if the text file is in local storage
// Here the document model is updated by converting the contents of the text file
// (code omitted, it is actually a method in the MyDocument class)
// ...
} catch {
// Produce error message: cannot access text file
// The error message is always produced if the text file is in iCloud storage!
}
// Save and close the document with standard code, e.g.:
doc.save(to: url, for: .forCreating) { (saveSuccess) in
guard saveSuccess else { return }
doc.close(completionHandler: { (closeSuccess) in
guard closeSuccess else { return }
})
// Reveal and import the document
self.revealDocument(at: url, importIfNeeded: true) { (revealedDocumentURL, error) in
if let error = error {
// Handle the error appropriately
return
}
// Present the Document View Controller for the revealed URL
self.presentDocument(at: revealedDocumentURL!)
}
}
}
info.plist文件将自定义文档和public.text声明为文档类型(具有相应的角色和处理程序排名),并将自定义文档声明为导出的UTI。如果选择的文件是自定义文档,则无论文件是本地文件还是iCloud,一切正常。
由于导入在文件位于本地存储时有效,我认为这可能是iCloud权限的问题,即使Apple文档为UIDocumentBrowserViewController
状态:
系统会自动为您处理对iCloud的访问;你没有 需要启用应用的iCloud功能。
然而,尝试将iCloud功能添加到我的应用程序的权利并没有解决问题(实际上使情况变得更糟,因为完全相同的代码现在在默认情况下保存新创建的文档应用程序的iCloud容器,不文档浏览器使用的相同iCloud Drive位置,以便所有文档对浏览器“不可见” - 但我离题了......)。
另一个“有趣”元素是我还在应用程序中实现了UIDocumentPickerViewController
,以便将文本文件中的其他内容导入到已打开的自定义文档中。我使用的代码与上面的代码基本相同......它完美无缺,无论文本文件是在本地存储还是在iCloud中!这可能会强化该问题与UIDocumentBrowserViewController
的特定权限问题相关联的观点。
因此,总结一下:如何访问存储在iCloud中的文本文件的内容并将其转换为我的应用程序的自定义文档?提前感谢您提出任何建议(如果问题的制定存在问题,请保持温和 - 这是我潜伏数月之后的第一个stackoverflow问题!)。
答案 0 :(得分:2)
我不是百分百确定,但我相信您需要在该网址上调用startAccessingSecurityScopedResource
来使用文档浏览器提供给您的沙盒扩展程序。完成后不要忘记调用stopAccessing
以免泄漏内核资源。另外,如果您没有真正编辑该文档,那么您可能正在寻找UIDocumentPickerViewController
?用户打开文件然后最终编辑另一个文件是很奇怪的。启动新文档,然后使用选择器将文本文件导入其中是不是更好的用户体验?
答案 1 :(得分:0)
小片段:(Swift 5.x)
public func documentBrowser(_ controller: UIDocumentBrowserViewController,
didPickDocumentsAt documentURLs: [URL]) {
dismiss(animated: true, completion: nil)
self.importAll(urls: documentURLs)
}
final func importAll(urls: [URL]) {
//TODO: use timer/loop/async stuff..
// for multiple files..
urls.forEach { (url: URL) in
let secured = url.startAccessingSecurityScopedResource()
= myImportInSessionFrom(url: url)
if secured { url.stopAccessingSecurityScopedResource() }
}
}