如何在UIDocumentBrowserVC中自动加载上次使用的UIDocument?
解决UIDocumentBrowserVC启动自动加载上次文档的问题
我之前也踩过这个坑,直接在viewDidLoad里调用presentDocument(at:)确实经常没效果,而且直接存URL到UserDefaults也容易出问题,给你梳理下可行的解决步骤:
一、正确持久化文档URL:用Bookmark代替直接存URL
直接存储文件URL到UserDefaults非常不可靠——尤其是涉及iCloud文件或沙盒内文件时,系统可能修改文件路径,导致你下次读取的URL失效,这大概率就是你触发checkResourceIsReachable()报错的原因。正确做法是把URL转换成安全的bookmark数据存储:
存储Bookmark的代码
// 用户打开/保存文档后,将当前文档URL转成bookmark持久化 func saveLastDocumentURL(_ url: URL) { do { // 若涉及iCloud或外部文件,需开启withSecurityScope选项 let bookmarkData = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) UserDefaults.standard.set(bookmarkData, forKey: "LastDocumentBookmark") } catch { print("保存bookmark失败: \(error.localizedDescription)") } }
从Bookmark恢复URL的代码
func restoreLastDocumentURL() -> URL? { guard let bookmarkData = UserDefaults.standard.data(forKey: "LastDocumentBookmark") else { return nil } var isStale = false do { let url = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale) // 若bookmark过期,重新保存新的bookmark if isStale { try saveLastDocumentURL(url) } // 针对需要权限的文件,启动安全范围访问 if url.startAccessingSecurityScopedResource() { defer { url.stopAccessingSecurityScopedResource() } } return url } catch { print("恢复bookmark失败: \(error.localizedDescription)") // 清空无效的存储数据 UserDefaults.standard.removeObject(forKey: "LastDocumentBookmark") return nil } }
二、选择正确的时机调用presentDocument(at:)
viewDidLoad阶段,UIDocumentBrowserViewController还未完成初始化,内部状态没准备好,此时调用presentDocument(at:)不会生效。你应该在浏览器完成初始加载后调用,也就是实现UIDocumentBrowserViewControllerDelegate的browserDidFinishInitialLoad(_:)方法:
步骤1:设置代理
在你的UIDocumentBrowserVC子类的viewDidLoad中设置代理:
override func viewDidLoad() { super.viewDidLoad() self.delegate = self // 其他初始化代码... }
步骤2:实现代理方法,自动加载上次文档
extension YourDocumentBrowserVC: UIDocumentBrowserViewControllerDelegate { func browserDidFinishInitialLoad(_ browser: UIDocumentBrowserViewController) { // 恢复上次存储的文档URL guard let lastDocumentURL = restoreLastDocumentURL() else { return } // 检查文档是否可达 do { let isReachable = try lastDocumentURL.checkResourceIsReachable() if isReachable { self.presentDocument(at: lastDocumentURL) } else { print("文档已不存在,清空存储记录") UserDefaults.standard.removeObject(forKey: "LastDocumentBookmark") } } catch { print("检查文档可达性失败: \(error.localizedDescription)") } } }
三、额外注意事项
- 若文档存储在iCloud Drive,确保已在Xcode的
Signing & Capabilities中开启iCloud能力,并勾选iCloud Documents。 - 调用
presentDocument(at:)时,URL对应的文档类型必须和你在Info.plist中配置的CFBundleDocumentTypes匹配,否则也会无效。 - 对于安全范围资源,务必在访问前后调用
startAccessingSecurityScopedResource()和stopAccessingSecurityScopedResource(),避免权限问题。
这样调整后,启动时就能自动加载上次的文档,而且URL持久化的可靠性也会大幅提升。
内容的提问来源于stack exchange,提问作者A. Vage
相关产品推荐
相关产品推荐

