SwiftUI:使用切换删除单元格时索引超出范围 [英] SwiftUI: Index out of range when deleting cells with toggle

查看:31
本文介绍了SwiftUI:使用切换删除单元格时索引超出范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在删除包含 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆