繁体   English   中英

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

[英]SwiftUI ForEach index out of range error when removing row

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

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 中

问题描述

索引超出范围错误是因为init(_ data: Range<Int>, content: @escaping (Int) -> Content) ForEach初始化器不允许我们动态修改数组。 为此,我们需要使用init(_ data: Data, content: @escaping (Data.Element) -> Content)初始值设定项,如 @Asperi 在评论中所解释 但是,正如@JacobCXDev 在回复中所澄清的那样,它在嵌套绑定的这种情况下也不起作用。

解决方法(我找到了解决方案,见下文)

使用自定义绑定和附加状态。 自定义绑定解决了嵌套绑定上的ForEach问题。 最重要的是,您需要在每次触摸自定义绑定后修改状态以重新渲染屏幕。 以下是一个简化的(未经测试的)代码示例。

@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)
}

解决方案(2020 年 7 月 10 日新增)

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

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)
    }
}

class Node: ObservableObject, Identifiable {
    @Published var xString: String
    let id: String = UUID().uuidString

    init(xString: String) {
        self.xString = xString
    }
}

它按以下代码工作。

 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()
    })}

}}

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

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

任何更好的解决方案?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM