SwiftUI:取消查看导致索引超出范围错误

SwiftUI:取消查看导致索引超出范围错误,swiftui,swiftui-list,Swiftui,Swiftui List,这件事让我毛骨悚然,我希望有人能告诉我哪里出了问题 目标是我需要能够管理项目的动态列表(即列表可以增长或收缩),其中每个项目的属性都可以调整(编辑),并且项目与给定的父项相关 在下面的简略代码中,我调用了item单元格,它属于一行。一行可以有许多单元格,每个单元格都有用户可以更改的数量。这是我的代码的一个节略版本,我希望它能让关系标签更清晰一些,但关键的是,它给了我同样的错误,那就是: 如果单元格数量小于原始数量(即,在本例中为3或更少),则每当关闭视图时,应用程序都会因“索引超出范围”错误而崩

这件事让我毛骨悚然,我希望有人能告诉我哪里出了问题

目标是我需要能够管理项目的动态列表(即列表可以增长或收缩),其中每个项目的属性都可以调整(编辑),并且项目与给定的父项相关

在下面的简略代码中,我调用了item单元格,它属于一行。一行可以有许多单元格,每个单元格都有用户可以更改的数量。这是我的代码的一个节略版本,我希望它能让关系标签更清晰一些,但关键的是,它给了我同样的错误,那就是:

如果单元格数量小于原始数量(即,在本例中为3或更少),则每当关闭视图时,应用程序都会因“索引超出范围”错误而崩溃。到目前为止,可以添加或删除单元格而不会出现任何问题,并且在更改单元格项的数量时,我不会出现此错误。我浏览了很多博客,没有找到任何人遇到过这个问题——似乎大多数索引超出范围的帖子都是在实际修改列表时出现的,我的错误只发生在列表缩小后被驳回时

我在下面附上了一些示例代码-您应该能够剪切/粘贴并试用

我知道calculateTotals()是草图;请不要在总数中添加字母或标点符号-这只是为了测试绑定是否正确冒泡:)

单元格

struct Cell: Identifiable {
    var amount: String
    var id = UUID()

    init(_ amount: String = "0.00"){
        self.amount = amount
    }
}

class Row: ObservableObject {
    @Published var cells: [Cell]

    init(){
        self.cells = [
            Cell("10"),
            Cell("15"),
            Cell("20"),
            Cell("25")]
    }
}
struct ContentView: View {
    @State private var displayAmounts = false

    var body: some View {
        NavigationView {
            Button(action: {
                self.displayAmounts.toggle()
            }) {
                Text("View amounts")
            }
        }
        .sheet(isPresented: self.$displayAmounts) {
            CellSheet()
        }
    }
}
ContentView

class Row: ObservableObject {
    @Published var cells: [Cell]

    init(){
        self.cells = [
            Cell("10"),
            Cell("15"),
            Cell("20"),
            Cell("25")]
    }
}
struct ContentView: View {
    @State private var displayAmounts = false

    var body: some View {
        NavigationView {
            Button(action: {
                self.displayAmounts.toggle()
            }) {
                Text("View amounts")
            }
        }
        .sheet(isPresented: self.$displayAmounts) {
            CellSheet()
        }
    }
}
单元格页

struct CellSheet: View {
    @ObservedObject var row: Row = Row()

    private func deleteCell(at offsets: IndexSet) {
        self.row.cells.remove(atOffsets: offsets)
    }

    private func calculateTotals() -> String {
        var total = Double("0.00")!

        for cell in self.row.cells {
            if( "" != cell.amount ) {
                total += Double(cell.amount)!
            }
        }

        return String("\(total)")
    }

    var body: some View {
        VStack{
            List {
                ForEach(row.cells.indices, id: \.self){ i in
                    CellItem(amount: self.$row.cells[i].amount)
                }.onDelete(perform: deleteCell)
            }
            Button(action: {
                self.row.cells.append(Cell())
            }) {
                Text("Add new cell")
            }

            Text(calculateTotals())
        }
    }
}
CellItem-这里有些奇怪:如果我用HStack包装文本字段,那么如果删除单元格,应用程序会立即崩溃——即使单元格总数大于原始数量(4)

我真的不知道这是怎么发生的。很明显,Swift试图访问一个不存在的索引(如果我删除绑定并只输出值,那就没有问题),但我不明白为什么在视图被取消时会出现问题。我猜斯威夫特在内存中缓存一些东西?HStack包装问题也很特殊

无论如何,我对斯威夫特还比较陌生,所以我可能忽略了一些显而易见的东西。另外,我运行的是XCode 11.4.1,目标是iOS 13.4


您应该能够将所有这些代码直接提升到一个新项目中,它将被编译。任何帮助都会得到感激:)

好的,在创建这篇文章几分钟后(我已经做了几天),我想我有一个解决方案。我在ContentView中修改了列表(),如下所示:

List {
    ForEach(Array(row.cells.enumerated()), id:\.1.id) { (i, cell) in
        CellItem(amount: self.$row.cells[i].amount)
    }.onDelete(perform: deleteCell)
}

这是基于我认为(?)枚举()更适合数组长度可变的情况。通过上述实现,HStack崩溃也得到了解决。也许有人可以给这篇文章添加更多的内容。

好的,在写了这篇文章几分钟后(我已经写了几天),我想我有了一个解决方案。我在ContentView中修改了列表(),如下所示:

List {
    ForEach(Array(row.cells.enumerated()), id:\.1.id) { (i, cell) in
        CellItem(amount: self.$row.cells[i].amount)
    }.onDelete(perform: deleteCell)
}

这是基于我认为(?)枚举()更适合数组长度可变的情况。通过上述实现,HStack崩溃也得到了解决。也许有人可以给它添加更多的上下文。

让我充满希望-当它是数组中的最后一项时崩溃会返回。让我充满希望-当它是数组中的最后一项时崩溃会返回。