SwiftUI:使用切换删除单元格时索引超出范围 [英] SwiftUI: Index out of range when deleting cells with toggle
问题描述
我在删除包含 Toggle 的单元格时遇到问题.
I have problems with deleting cells that contain a Toggle.
我的模型如下所示:
class Model: ObservableObject {
@Published var items: [Item]
init(items: [Item]) {
self.items = items
}
}
struct Item: Identifiable {
var id = UUID()
var text: String
var isImportant: Bool
}
我的观点是:
struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
List {
ForEach(model.items) {item in
ItemCell(item: item).environmentObject(self.model)
}
.onDelete(perform: deleteItem)
}
}
func deleteItem(indexSet: IndexSet) {
indexSet.forEach({model.items.remove(at: $0)})
}
}
struct ItemCell: View {
@EnvironmentObject var model: Model
var item: Item
var itemIndex: Int {model.items.firstIndex(where: {$0.id == item.id})!}
var body: some View {
Toggle(isOn: $model.items[itemIndex].isImportant) {
Text(item.text)
}
}
}
如您所见,我使用 @EnvironmentObject
.每次尝试删除单元格时,都会在 AppDelegate
中收到此错误消息:
As you can see I use @EnvironmentObject
. Every time I try to delete a cell, I get this error message shown in the AppDelegate
:
Thread 1: Fatal error: Index out of range
我认为问题在于我如何将数据从 ContentView()
传递到 ItemCell()
.我还尝试将 ItemCell()
的代码集成到 ForEach
的闭包中,但这不起作用.
I assume the problem is how I pass the data from my ContentView()
to the ItemCell()
. I also tried to integrate the code of ItemCell()
into the closure of the ForEach
but this didn't work.
希望有人能帮助我.
附加问题:注入 EnvironmentObject (.environmentObject(self.model)
) 的目的是什么?我不明白什么时候用,什么时候不用.在我的理解中,EnvironmentObject 是一个全局对象,它存在于环境中并且总是更新信息,独立于视图.
Additional question: What is the purpose of injection with EnvironmentObject (.environmentObject(self.model)
)? I don't understand when to use it and when not. In my understanding the EnvironmentObject is a global object that lives in the environment and has always updated information, independent on the View.
谢谢!妮可
更新:
我有另一个想法,但也行不通:ContentView
:
I had another idea, that didn't work either:
ContentView
:
ForEach(model.items.indices) {index in
ItemCell(item: self.$model.items[index]).environmentObject(self.model)
}
和ItemCell
:
@Binding var item: Item
var body: some View {
Toggle(isOn: $item.isImportant) {
Text(item.text)
}
}
有什么想法吗?
更新 2
这也不起作用:
ForEach(Array(model.items.enumerated()), id: \.element) {index, item in
ItemCell(item: self.$model.items[index]).environmentObject(self.model)
}
推荐答案
一个可能的解决方案是使用默认值而不是强制展开.当您删除列表中的一行时,其 ItemCell
视图可能仍存在于内存中.通过使用默认值,您可以防止崩溃(由于您无法再访问此视图,因此不会有操作错误项目的风险).
A possible solution is to use a default value instead of force-unwrapping. When you delete a row in the list, its ItemCell
view may still exist in memory. By using a default value you can prevent crashing (there's no risk of manipulating the wrong item as you can't access this view anymore).
var itemIndex: Int { model.items.firstIndex(where: { $0.id == item.id }) ?? 0 }
或者,您可以使用可选索引:
Alternatively, you can use an optional index:
struct ItemCell: View {
@EnvironmentObject var model: Model
var item: Item
var itemIndex: Int? { model.items.firstIndex(where: { $0.id == item.id }) }
var body: some View {
Group {
if itemIndex != nil {
Toggle(isOn: $model.items[itemIndex!].isImportant) {
Text(item.text)
}
}
}
}
}
这篇关于SwiftUI:使用切换删除单元格时索引超出范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!