SwiftUI onDelete()获取删除行ID重复异常求助
问题分析
你遇到的核心问题是:未将已标记删除的ID从列表数据源中排除,导致滑动删除后界面行重新显示,后续删除操作的索引指向了错误的元素;同时你的删除逻辑仅处理单个索引,且存在冗余代码。
解决方案
- 调整
filteredTodos的过滤规则,把已标记为待删除的ID排除在外,确保界面上删除的行真正消失; - 遍历
indexSet中的所有索引,批量收集待删除ID,支持多选删除; - 移除无意义的冗余判断代码。
修改后的代码
import SwiftUI struct TodoItem: Identifiable { var id: String var todoID: String var todoName: String var isCompleted: Bool = false } final class TodoList: ObservableObject { @Published var items: [TodoItem] = [TodoItem]() @Published var appIsLoading: Bool = false var sortedTodos: [TodoItem] { return self.items.sorted { $0.todoName < $1.todoName } } func fetchTodos() { self.appIsLoading = true DispatchQueue.main.asyncAfter(deadline: .now() + 1) { self.items = [ TodoItem(id: "aaa", todoID: "aaa", todoName: "Take Out Trash", isCompleted: false), TodoItem(id: "bbb", todoID: "bbb", todoName: "Clean Room", isCompleted: true), TodoItem(id: "ccc", todoID: "ccc", todoName: "Check Mail", isCompleted: false), TodoItem(id: "ddd", todoID: "ddd", todoName: "Walk The Dog", isCompleted: true) ] self.appIsLoading = false } } } struct TodoListView: View { var todosArray: [TodoItem] var appIsLoading: Bool @State private var hideCompleted: Bool = false @State private var arrayOfTodosToDelete: [String] = [String]() private var filteredTodos: [TodoItem] { return self.todosArray.filter { todo in // 新增:排除已标记待删除的ID !arrayOfTodosToDelete.contains(todo.todoID) && !(self.hideCompleted && todo.isCompleted) } } func deleteTodo(atOffsets indexSet: IndexSet) { // 遍历所有待删除的索引,收集ID indexSet.forEach { index in let todo = filteredTodos[index] arrayOfTodosToDelete.append(todo.todoID) } } func onSubmit() { print("Current Array is \(self.arrayOfTodosToDelete)") // 这里处理网络同步逻辑 // 同步完成后可以清空待删除数组,或者更新原数据源 // arrayOfTodosToDelete.removeAll() } var body: some View { ZStack { List { ForEach(filteredTodos) { todo in Text(todo.todoName) }.onDelete(perform: deleteTodo) } if appIsLoading { Text("Loading") } }.navigationTitle("Todos") .toolbar(content: { ToolbarItem(placement: .topBarLeading) { Button(action: { withAnimation { self.hideCompleted.toggle() } }, label: { Text("Hide") }) } ToolbarItem(placement: .topBarTrailing) { Button(action: { self.onSubmit() }, label: { Text("Save") }) } }) } } struct ContentView: View { @StateObject var todosList = TodoList() private func getData() { self.todosList.fetchTodos() } var body: some View { ZStack { NavigationView { TodoListView(todosArray: todosList.sortedTodos, appIsLoading: todosList.appIsLoading) } }.onAppear { self.getData() } } } #Preview { ContentView() }
关键修改点
- 过滤逻辑:在
filteredTodos中新增!arrayOfTodosToDelete.contains(todo.todoID),确保已标记删除的元素不再显示在界面上; - 删除逻辑:用
indexSet.forEach遍历所有待删除索引,批量收集ID,同时移除了冗余的todoToDelete变量和无用判断; - 界面更新:现在滑动删除后,行会真正从界面消失,后续删除操作的索引会正确对应剩余元素。
内容的提问来源于stack exchange,提问作者Clay_F
相关产品推荐
相关产品推荐

