删除行时,SwiftUI ForEach索引超出范围错误 [英] SwiftUI ForEach index out of range error when removing row

查看:61
本文介绍了删除行时,SwiftUI ForEach索引超出范围错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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 索引错误.我已经尝试解决了几个小时,但无济于事.

The issue I am facing is that upon calling self.record.nodes.removeLast(), the application crashes with an Index out of range error. I've been trying to solve this for hours, but to no avail.

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

I originally used onDelete, however that produced the same issue.

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

The project can be found at https://github.com/jacobcxdev/Timekeeper, with this error happening in RecordDetailView.swift.

推荐答案

问题描述

发生索引超出范围错误是因为 ForEach init(_ data:Range< Int>,content:@escaping(Int)-> Content)初始化程序不允许我们动态修改数组.为此,我们需要使用 init(_ data:Data,content:@escaping(Data.Element)-> Content)初始化程序,如

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.

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

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

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

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

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

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

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

这篇关于删除行时,SwiftUI ForEach索引超出范围错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆