在 ForEach 中删除数组元素时,SwiftUI 没有索引 [英] SwiftUI out of index when deleting an array element in ForEach
问题描述
我在这里查看了不同的问题,但不幸的是我找不到答案.这是我的代码:
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.swift
的 body
或
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屋!