SwiftUI ForEach index out of range error when removing row

前端 未结 3 882
日久生厌
日久生厌 2021-01-06 00:39

I have a ForEach block and a Stepper embedded in a List view. The contents of the List view\'s first section is as follow

相关标签:
3条回答
  • 2021-01-06 01:29

    Problem Description

    The index out of range error occurs because init(_ data: Range<Int>, content: @escaping (Int) -> Content) initializer of ForEach does not allow us to modify the array dynamically. For that, we need to use init(_ data: Data, content: @escaping (Data.Element) -> Content) initializer as @Asperi explained in the comment. However, it does not work either in this situation, where bindings are nested, as @JacobCXDev clarified in the reply.

    Workaround (I found a better solution, see below)

    Use custom bindings and an additional state. The custom bindings solve the issue of ForEach over nested bindings. On top of that, you need to modify a state after every touch on the custom binding to re-render the screen. The following is a simplified (untested) code sample.

    @State private var xString: String
    

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

    Solution (added on July 10, 2020)

    Just define a view struct for the children like the following.

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

    struct NodeView: View {
        @ObservedObject var node: Node
    
        var body: some View {
            TextField("X", text: self.$node.xString)
        }
    }
    
    0 讨论(0)
  • 2021-01-06 01:37

    I had a same problem i solve with adding if condition before ForEach.

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

    any better solution?

    0 讨论(0)
  • 2021-01-06 01:42

    It works as the following codes.

     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()
        })}
    
    }}
    
    0 讨论(0)
提交回复
热议问题