删除行时SwiftUI ForEach索引超出范围错误

时间:2019-11-26 23:04:00

标签: ios swift swiftui

我在ForEach视图中嵌入了一个Stepper块和一个ListList视图的第一部分的内容如下:

ForEach(record.nodes.indices, id: \.self) { index in
    HStack {
        TextField("X", text: self.$record.nodes[index].xString)
        Spacer()
        Divider()
        TextField("Y", text: self.$record.nodes[index].yString)
        Spacer()
    }
}
Stepper("± node", onIncrement: {
    self.record.nodes.append(Node(x: 0, y: 0))
}, onDecrement: {
    self.record.nodes.removeLast()
})

我面临的问题是,调用self.record.nodes.removeLast()时,应用程序崩溃,并显示Index out of range错误。我已经尝试解决了几个小时,但无济于事。

我最初使用onDelete,但是产生了同样的问题。

可以在https://github.com/jacobcxdev/Timekeeper上找到该项目,此错误发生在RecordDetailView.swift中。

3 个答案:

答案 0 :(得分:5)

问题描述

发生索引超出范围错误是因为init(_ data: Range<Int>, content: @escaping (Int) -> Content)的{​​{1}}初始化程序不允许我们动态修改数组。为此,我们需要使用ForEach初始化程序,如the comment中的@Asperi所述。但是,这在嵌套绑定的情况下也不起作用,正如@JacobCXDev在回复中阐明的那样。

解决方法(我找到了更好的解决方案,请参见下文)

使用custom bindings和其他状态。自定义绑定解决了嵌套绑定上的init(_ data: Data, content: @escaping (Data.Element) -> Content)问题。最重要的是,您每次触摸自定义绑定后都需要修改状态以重新渲染屏幕。以下是一个简化的(未经测试的)代码示例。

ForEach

@State private var xString: String

解决方案(于2020年7月10日添加)

只需为孩子定义一个视图结构,如下所示:

ForEach(record.nodes) { node in
    let xStringBinding = Binding(
        get: { node.xString },
        set: {
            node.xString = $0
            self.xString = $0
        }
    )
    TextField("X", text: xStringBinding)
}

ForEach(record.nodes) { node in
    NodeView(node: node)
}

答案 1 :(得分:2)

它用作以下代码。

 struct Node {
var xString: String = "x"
var yString: String = "y"
var x: Int
var y: Int
 }

 struct RecordsNode {
var nodes : [Node]
 }

struct ContentView: View {



@State var record: RecordsNode = RecordsNode(nodes: [Node(x: 11, y: 11)])

var body: some View {

    Group{
    ForEach(record.nodes.indices, id: \.self) { index in
        HStack {
            TextField("X", text: self.$record.nodes[index].xString)
            Spacer()
            Divider()
            TextField("Y", text: self.$record.nodes[index].yString)
            Spacer()
        }
    }
    Stepper("± node", onIncrement: {
        self.record.nodes.append(Node(x: 0, y: 0))
    }, onDecrement: {
        self.record.nodes.removeLast()
    })}

}}

答案 2 :(得分:0)

我在ForEach之前添加if条件解决了相同的问题。

if (!IsDeleting) {
  ...
  .OnDecrement{
     IsDeleting := true
   }
}

有更好的解决方案吗?