FileManager .removeItem(at:)无完成回调,如何判断文件删除完成以更新列表?
根本原因
你的崩溃和文件删除逻辑无关,removeItem(at:) 确实是同步接口,执行完成时文件已经被实际删除。
从崩溃堆栈可以看出,问题出在 SwiftUI 内部的 List 数据源状态不匹配:onDelete 回调执行时,SwiftUI 默认期望你对数据源数组做局部删除操作(即删除对应索引的元素),你直接调用 updateURLs() 全量替换了整个数据源数组,导致 List 内部维护的编辑状态和实际数据源不一致,触发了 SwiftUI 内部断言崩溃。你加的延迟能生效,本质是等 onDelete 对应的编辑生命周期完全结束后才更新数据源,避免了状态冲突。
解决方案
方案1:优先适配 List 编辑规则(推荐)
先局部更新数据源满足 SwiftUI 的编辑预期,再执行文件删除操作,最后异步全量同步数据源保证准确性:
.onDelete { row in guard let i = row.first, let fileURL = urls[safe: i] else { return } // 先移除数据源对应元素,匹配List编辑预期 urls.remove(at: i) do { try FileManager.default.removeItem(at: fileURL) // 异步全量同步,避免和当前编辑流程冲突 DispatchQueue.main.async { updateURLs() } } catch { print(error.localizedDescription) // 文件删除失败时回滚数据源 urls.insert(fileURL, at: i) } }
方案2:异步更新数据源
如果不想修改现有逻辑,只需要把 updateURLs() 包在主队列异步调用里即可,不需要固定时长延迟:
try FileManager.default.removeItem(at: fileURL) DispatchQueue.main.async { updateURLs() }
主队列是串行执行的,async 提交的任务会等当前 onDelete 编辑流程完全结束后再执行,不会产生状态冲突,也没有多余的等待时间。
内容的提问来源于stack exchange,提问作者LinusG.
相关产品推荐
相关产品推荐

