将UIDocument保存到新URL时不使用FileManager如何避免文件名冲突
UIDocument保存时静默覆盖问题解决方案
问题背景
使用FileManager将文件保存到App沙箱时,可通过FileManager的fileExists(atPath:)方法检查文件是否存在。
但直接使用UIDocument的保存方法save(to:for:completion)时,传入已存在的文件URL会直接覆盖原有内容且无任何提示,极易误操作导致文件丢失。且UIDocument的公开方法默认仅返回操作成功/失败的布尔值,不会返回具体错误原因。
常见疑问解答
这类文件存在性检查是否只能通过FileManager或其他框架实现?
答案是肯定的:UIDocument本身没有内置文件存在校验逻辑,要避免静默覆盖,必须在调用save方法前主动通过FileManager做存在性检查,无其他官方内置方案。
问题复现代码
1. 定义Document子类
class TextDocument: UIDocument { var text: String? }
2. 获取文档目录URL
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
3. 创建2个文档并保存
let doc1 = TextDocument(fileURL: documentsDirectory .appendingPathComponent("File 1") .appendingPathExtension("txt")) let doc2 = TextDocument(fileURL: documentsDirectory .appendingPathComponent("File 2") .appendingPathExtension("txt")) doc1.save(to: doc1.fileURL, for: .forCreating) { success in print(success) // 输出 true } doc2.save(to: doc2.fileURL, for: .forCreating) { success in print(success) // 输出 true }
4. 问题点:将doc1保存到doc2的URL时会无提示覆盖doc2
doc1.save(to: doc2.fileURL, for: .forOverwriting) { success in print(success) // 输出 true,此时doc2原有内容已被覆盖 }
最优实践方案
方案1:封装带存在性校验的安全保存方法
给UIDocument添加扩展,统一在保存前做校验:
extension UIDocument { /// 带文件存在校验的安全保存方法 /// - Parameters: /// - url: 保存目标路径 /// - saveOperation: 保存类型 /// - completion: 完成回调,success为操作是否成功,fileExists为目标路径是否已存在文件 func safeSave(to url: URL, for saveOperation: UIDocument.SaveOperation, completion: @escaping (_ success: Bool, _ fileExists: Bool) -> Void) { let fileExists = FileManager.default.fileExists(atPath: url.path) // 创建模式下文件已存在,直接拦截不执行保存 if saveOperation == .forCreating && fileExists { completion(false, true) return } // 校验通过后执行原生保存逻辑 self.save(to: url, for: saveOperation) { success in completion(success, fileExists) } } }
使用时如果是创建新文件场景,直接调用safeSave传入.forCreating即可自动拦截覆盖场景;如果是需要覆盖的场景,可先根据回调的fileExists字段给用户弹出二次确认提示,用户确认后再执行保存操作。
方案2:获取UIDocument操作的具体错误
如果需要拿到操作失败的具体原因,可在UIDocument子类中重写handleError(_:userInteractionPermitted:)方法,系统会将所有操作产生的错误传递到该方法中,可在此处统一捕获处理错误信息。
内容的提问来源于stack exchange,提问作者MH175
相关产品推荐
相关产品推荐

