如何无需用户交互将文件保存至documentDirectory并实现自动更新
实现自动更新Shortcuts文件夹中的JSON文件
完全可以实现这个需求,核心思路是保存用户首次选择的Shortcuts文件夹中目标文件的持久化访问权限,后续直接通过该权限写入数据,无需再弹出文件选择器。以下是具体实现步骤和代码:
1. 存储目标文件的URL
首先需要把用户首次选择的文件URL保存到UserDefaults,确保App重启后仍能访问:
private var targetFileURL: URL? { get { guard let urlStr = UserDefaults.standard.string(forKey: "SavedShortcutsFileURL") else { return nil } return URL(string: urlStr) } set { UserDefaults.standard.set(newValue?.absoluteString, forKey: "SavedShortcutsFileURL") } }
2. 首次保存逻辑(让用户选择Shortcuts文件夹)
首次保存时,弹出文件选择器让用户指定Shortcuts文件夹中的目标文件(支持新建):
func firstTimeSave(with data: Data) { // 初始化文件选择器,仅允许选择JSON文件 let picker = UIDocumentPickerViewController( documentTypes: ["public.json"], in: .open ) picker.delegate = self picker.allowsMultipleSelection = false picker.modalPresentationStyle = .formSheet present(picker, animated: true) }
3. 处理文件选择结果,获取持久化权限
实现UIDocumentPickerDelegate方法,保存目标URL并完成首次写入:
extension YourViewController: UIDocumentPickerDelegate { func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { guard let selectedURL = urls.first else { return } // 请求持久化访问权限(必须步骤,否则App重启后无法访问该文件) guard selectedURL.startAccessingSecurityScopedResource() else { print("无法获取文件访问权限") return } // 保存URL到本地 targetFileURL = selectedURL // 写入初始数据 do { try data.write(to: selectedURL, options: .atomic) print("首次保存成功:\(selectedURL)") } catch { print("首次保存失败:\(error.localizedDescription)") } // 结束临时访问(后续更新时会重新开启) selectedURL.stopAccessingSecurityScopedResource() } }
4. 后台自动更新逻辑
当用户点击「更新文件」按钮时,直接通过保存的URL写入数据:
func updateExistingFile(with data: Data) { guard let targetURL = targetFileURL else { print("请先完成首次保存操作") return } // 重新开启文件访问权限 guard targetURL.startAccessingSecurityScopedResource() else { print("无法访问目标文件") return } defer { // 确保访问结束后释放权限 targetURL.stopAccessingSecurityScopedResource() } // 直接覆盖写入数据 do { try data.write(to: targetURL, options: .atomic) print("文件更新成功:\(targetURL)") } catch { print("更新失败:\(error.localizedDescription)") } }
5. 按钮点击逻辑整合
在「保存/更新」按钮的点击事件中,判断是否已有保存的URL,执行对应操作:
@IBAction func saveUpdateButtonTapped(_ sender: UIButton) { // 替换成你实际获取用户数据的逻辑 guard let userData = try? JSONSerialization.data(withJSONObject: yourUserData, options: .prettyPrinted) else { return } if targetFileURL != nil { updateExistingFile(with: userData) } else { firstTimeSave(with: userData) } }
注意事项
- 必须在
Info.plist中添加JSON文件支持:添加CFBundleDocumentTypes数组,包含public.json类型 - 如果Shortcuts文件夹在iCloud Drive中,需确保App已开启iCloud权限(在Xcode Capabilities中配置iCloud Documents)
- 每次访问安全范围资源(即通过
startAccessingSecurityScopedResource)后,必须调用stopAccessingSecurityScopedResource释放权限
内容的提问来源于stack exchange,提问作者Sandra Passani
相关产品推荐
相关产品推荐

