我在ForEach
视图中嵌入了一个Stepper
块和一个List
。 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中。
答案 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
只需为孩子定义一个视图结构,如下所示:
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
}
}
有更好的解决方案吗?