在 ForEach 中删除数组元素时,SwiftUI 没有索引 [英] SwiftUI out of index when deleting an array element in ForEach

查看:38
本文介绍了在 ForEach 中删除数组元素时,SwiftUI 没有索引的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里查看了不同的问题,但不幸的是我找不到答案.这是我的代码:

I looked through different questions here, but unfortunately I couldn't find an answer. This is my code:

SceneDelegate.swift

...
let contentView = ContentView(elementHolder: ElementHolder(elements: ["abc", "cde", "efg"]))
...
window.rootViewController = UIHostingController(rootView: contentView)

ContentView.swift

class ElementHolder: ObservableObject {

    @Published var elements: [String]

    init(elements: [String]) {
        self.elements = elements
    }
}

struct ContentView: View {

    @ObservedObject var elementHolder: ElementHolder

    var body: some View {
        VStack {

            ForEach(self.elementHolder.elements.indices, id: \.self) { index in
                SecondView(elementHolder: self.elementHolder, index: index)
            }

        }
    }
}

struct SecondView: View {

    @ObservedObject var elementHolder: ElementHolder
    var index: Int

    var body: some View {
        HStack {
            TextField("...", text: self.$elementHolder.elements[self.index])
            Button(action: {
                self.elementHolder.elements.remove(at: self.index)
            }) {
                Text("delete")
            }
        }
    }

}

按下删除按钮时,应用程序崩溃并出现索引越界错误.

When pressing on the delete button, the app is crashing with a Index out of bounds error.

有两件奇怪的事情,app在什么时候运行

There are two strange things, the app is running when

1) 删除 VStack 并将 ForEach 放入 ContentView.swiftbody

1) you remove the VStack and just put the ForEach into the body of the ContentView.swift or

2) 你把SecondView的代码直接放到ForEach

2) you put the code of the SecondView directly to the ForEach

只有一件事:我真的需要ObservableObject,这个代码只是另一个代码的简化.

Just one thing: I really need to have the ObservableObject, this code is just a simplification of another code.

更新

我更新了我的代码并将 Text 更改为 TextField,因为我不能只传递一个字符串,我需要双向连接.

I updated my code and changed Text to a TextField, because I cannot pass just a string, I need a connection in both directions.

推荐答案

这里有一个可能的解决方案 - 使 SecondView 的主体不依赖于 ObservableObject.

Here is possible solution - make body of SecondView undependable of ObservableObject.

使用 Xcode 11.4/iOS 13.4 测试 - 没有崩溃

Tested with Xcode 11.4 / iOS 13.4 - no crash

struct SecondView: View {

    @ObservedObject var elementHolder: ElementHolder
    var index: Int
    let value: String

    init(elementHolder: ElementHolder, index: Int) {
        self.elementHolder = elementHolder
        self.index = index
        self.value = elementHolder.elements[index]
    }

    var body: some View {
        HStack {
            Text(value)     // not refreshed on delete
            Button(action: {
                self.elementHolder.elements.remove(at: self.index)
            }) {
                Text("delete")
            }
        }
    }
}

另一种可能的解决方案是不要在 SecondView 中观察 ElementHolder... 因为不需要显示和删除它 - 也不会崩溃

Another possible solution is do not observe ElementHolder in SecondView... for presenting and deleting it is not needed - also no crash

struct SecondView: View {

    var elementHolder: ElementHolder // just reference
    var index: Int

    var body: some View {
        HStack {
            Text(self.elementHolder.elements[self.index])
            Button(action: {
                self.elementHolder.elements.remove(at: self.index)
            }) {
                Text("delete")
            }
        }
    }
}

更新:文本字段的SecondView变体(仅更改文本字段本身)

Update: variant of SecondView for text field (only changed is text field itself)

struct SecondViewA: View {

    var elementHolder: ElementHolder
    var index: Int

    var body: some View {
        HStack {
            TextField("", text: Binding(get: { self.elementHolder.elements[self.index] },
                set: { self.elementHolder.elements[self.index] = $0 } ))
            Button(action: {
                self.elementHolder.elements.remove(at: self.index)
            }) {
                Text("delete")
            }
        }
    }
}

这篇关于在 ForEach 中删除数组元素时,SwiftUI 没有索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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