Swift中UIDocumentPicker选取的文件2-3分钟后过期无法访问如何解决
问题原因
- 你保存的路径指向App沙盒的
tmp临时目录,iOS系统会在App退出、内存不足或者定期清理时自动删除tmp目录下的文件,间隔一段时间后文件自然不存在。 - 如果选择的是App外部的文件,
UIDocumentPicker默认返回的URL仅持有临时访问权限,权限过期后就算文件本身存在,你也无法通过原URL访问,fileExists也会返回false。
解决方案
方案1:将选中文件复制到持久化目录(推荐,适合大多数场景)
拿到选中的文件URL后,立刻将文件复制到沙盒的Documents、Library这类不会被系统自动清理的持久化目录,之后统一使用新的保存路径访问文件。
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) { // 获取Documents目录路径 let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] // 生成目标存储URL,可自定义文件名避免重复 let targetUrl = docDir.appendingPathComponent(url.lastPathComponent) do { // 目标路径已存在则先删除或重命名 if FileManager.default.fileExists(atPath: targetUrl.path) { try FileManager.default.removeItem(at: targetUrl) } // 复制文件到持久化目录 try FileManager.default.copyItem(at: url, to: targetUrl) // 保存这个targetUrl的路径即可,不要用原tmp路径 UserDefaults.standard.set(targetUrl.path, forKey: "savedFilePath") } catch { print("文件保存失败:\(error)") } }
后续访问文件时直接读取你保存的持久化路径即可。
方案2:使用安全范围书签持久化访问权限(适合不想复制文件,直接访问外部存储文件的场景)
如果需要直接访问iCloud、其他App目录下的文件不想复制到自身沙盒,可以将URL转换为安全范围书签持久化存储,下次访问时用书签还原URL并开启访问权限。
// documentPicker回调中生成并保存书签 do { let bookmarkData = try url.bookmarkData(options: .suitableForBookmarkFile, includingResourceValuesForKeys: nil, relativeTo: nil) // 持久化存储bookmarkData UserDefaults.standard.set(bookmarkData, forKey: "savedFileBookmark") } catch { print("生成书签失败:\(error)") } // 访问文件时还原URL if let bookmarkData = UserDefaults.standard.data(forKey: "savedFileBookmark") { var isStale = false do { let savedUrl = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale) if !isStale { // 必须调用该方法获取访问权限 if savedUrl.startAccessingSecurityScopedResource() { defer { // 访问结束后释放权限 savedUrl.stopAccessingSecurityScopedResource() } let fileExist = FileManager.default.fileExists(atPath: savedUrl.path) // 后续执行分享等操作 } } } catch { print("还原书签失败:\(error)") } }
内容的提问来源于stack exchange,提问作者Bakdaulet Myrzakerov
相关产品推荐
相关产品推荐

