SwiftUI List中ForEach遍历删除后出现重复行数据异常问题
SwiftUI列表数据错乱、金额计算异常修复
异常根本原因
这个问题是三个代码逻辑错误共同导致的,其中ID生成错误是列表显示重复、条目内容异常变更的核心诱因:
- Identifiable协议的ID生成规则不符合要求
代码中新增Task时用String(taskStore.tasks.count + 1)作为条目ID,这个ID是动态根据当前数组长度计算的序号,不具备全局唯一性和稳定性:- 首次添加3条数据时,数组长度从0涨到3,三个条目ID分别为"1"(6月1日)、"2"(6月3日)、"3"(6月4日)
- 删除6月1日、6月4日条目后,数组只剩6月3日一条数据,数组长度变为1
- 新增6月2日条目时,计算出的ID为
String(1+1) = "2",和数组中原有6月3日条目的ID完全一致 - SwiftUI的
ForEach完全依靠Identifiable的id值区分不同条目,一旦出现重复ID,视图diff计算就会出错,错误复用原有条目的视图,表现为老条目内容被篡改、列表出现重复条目。
- 交互逻辑拆分错误导致金额计算时序混乱
代码把"计算费率"和"新增条目"的逻辑拆到了两个按钮上:显示文字的"Add Load"按钮只负责计算rate、累加总金额gp,实际触发新增条目的是一个没有文字的隐形按钮。点击顺序不对、点击间隔修改过输入值,都会导致存到Task里的金额和实际累加的金额不匹配。 - 删除逻辑存在漏洞导致总金额计算错误
现有删除逻辑只取offsets.first扣减一次金额,如果是编辑模式下多选删除条目,除了第一个选中的条目之外,其他被删条目的金额都不会从总金额gp中扣除,最终总金额必然和实际值不符。
对应修复方案
- 替换Task的ID生成规则,使用全局唯一的稳定ID,从根源解决列表渲染错乱问题
struct Task : Identifiable { // 初始化时自动生成全局唯一ID,永远不会和其他条目重复 var id = UUID() var toDoItem = String() var amount : Float = 0 }
- 合并按钮交互逻辑,把费率计算、总金额累加、新增条目的逻辑放到同一个按钮动作里,避免时序问题,同时删掉无用的空白隐形按钮
// 替换原来的两个按钮,逻辑合并 Button("Add Load") { // 先计算当前费率 rate = load1 + load2 // 累加总金额 gp += rate // 新增条目到列表 addNewToDo() // 新增完成后清空输入框,避免下次误操作 load1 = 0 load2 = 0 }
- 修改新增条目方法,不需要手动传入ID,初始化Task时UUID会自动生成
func addNewToDo() { let formatter = DateFormatter() formatter.dateFormat = "dd/MM/yyyy" let dayoftime = formatter.string(from: birthDate) let formatter2 = DateFormatter() formatter2.dateFormat = "HH:mm" let timeof1 = formatter2.string(from: time1) let timeof2 = formatter2.string(from: time2) taskStore.tasks.append(Task( toDoItem: "\(dayoftime) \(timeof1)-\(timeof2) total = \(rate) ", amount: rate )) }
- 修复删除逻辑,遍历所有待删除条目扣减金额,避免多选删除时总金额计算错误
func delete(at offsets : IndexSet) { // 遍历所有选中要删除的索引,逐个扣减对应金额 for index in offsets { let task = taskStore.tasks[index] gp -= task.amount } taskStore.tasks.remove(atOffsets: offsets) }
内容的提问来源于stack exchange,提问作者Ricky Chhetri
相关产品推荐
相关产品推荐

