QLPreviewControllerDelegate的didSaveEditedCopyOf返回无内容URL问题
问题根因
你的代码实现本身没有逻辑错误,问题出在未对modifiedContentsURL对应的临时文件做持久化处理:
- QLPreviewController返回的
modifiedContentsURL指向系统临时目录下的文件,系统仅保证该文件在previewController(_:didSaveEditedCopyOf:at:)回调执行期间可用,回调结束后系统会自动清理该临时文件 - 首次调用时能读取到数据是因为读取操作发生在回调执行窗口期内,后续调用时之前的临时文件已经被系统回收删除,自然无法读取到数据
- 你观察到的「第二次调用后副本被删除」的现象完全符合系统临时文件的清理逻辑
修复方案
只需要在回调触发时,立刻把临时URL对应的文件拷贝到App自身的沙箱目录(比如Documents、Caches目录下自定义路径)做持久化,后续使用时访问自行持久化后的路径即可,修改后的代码示例:
final class CustomQLPreviewDelegate: NSObject, QLPreviewControllerDelegate { // 建议直接返回持久化后的URL,比返回Data更节省内存,也避免大文件读取失败 var onSave: ( (Result<URL, Error>) -> Void )? func previewController(_ controller: QLPreviewController, editingModeFor previewItem: QLPreviewItem) -> QLPreviewItemEditingMode { .createCopy } func previewController(_ controller: QLPreviewController, didSaveEditedCopyOf previewItem: QLPreviewItem, at modifiedContentsURL: URL) { do { // 生成App沙箱内的持久化存储路径 let targetDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let targetFileName = "Edited_\(UUID().uuidString)_\(modifiedContentsURL.lastPathComponent)" let targetURL = targetDir.appendingPathComponent(targetFileName) // 回调窗口期内立刻把临时文件拷贝到持久化路径 try FileManager.default.copyItem(at: modifiedContentsURL, to: targetURL) onSave?(.success(targetURL)) } catch { onSave?(.failure(error)) } } }
系统Bug验证标准
如果完成上述修改后依然出现无法生成副本的问题,可以做两项验证确认是否为系统Bug:
- 确认App已获取对应文件的读写权限,iOS 13+如果访问App沙箱外的文件,需要确认持有对应的安全scope访问权限
- 打印每次回调返回的
modifiedContentsURL路径,如果后续回调返回的是已经被删除的旧路径,而非新生成的临时路径,即可判定为QLPreviewController的系统Bug,可以向苹果反馈
内容的提问来源于stack exchange,提问作者lacefarin
相关产品推荐
相关产品推荐

