在 SwiftUI 中将 TextField 与 ForEach 结合使用
Using TextField with ForEach in SwiftUI
我正在尝试使用 ForEach
显示文本字段的动态列表。以下代码按预期工作:我可以 add/remove 文本字段,并且绑定正确。但是,当我在 ObservableObject
视图模型中移动 items
时,它不再工作并且崩溃并出现 index out of bounds
错误。这是为什么?我怎样才能让它发挥作用?
struct ContentView: View {
@State var items = ["A", "B", "C"]
var body: some View {
VStack {
ForEach(items.indices, id: \.self) { index in
FieldView(value: Binding<String>(get: {
items[index]
}, set: { newValue in
items[index] = newValue
})) {
items.remove(at: index)
}
}
Button("Add") {
items.append("")
}
}
}
}
struct FieldView: View {
@Binding var value: String
let onDelete: () -> Void
var body: some View {
HStack {
TextField("item", text: $value)
Button(action: {
onDelete()
}, label: {
Image(systemName: "multiply")
})
}
}
}
我正在尝试使用的视图模型:
class ViewModel: Observable {
@Published var items: [String]
}
@ObservedObject var viewModel: ViewModel
我发现很多问题都涉及同一问题,但我无法解决我的问题。其中一些没有提到 TextField
,其他一些没有工作(不再?)。
非常感谢
通过检查 Binding
内的边界,您可以解决问题:
struct ContentView: View {
@ObservedObject var viewModel: ViewModel = ViewModel(items: ["A", "B", "C"])
var body: some View {
VStack {
ForEach(viewModel.items.indices, id: \.self) { index in
FieldView(value: Binding<String>(get: {
guard index < viewModel.items.count else { return "" } // <- HERE
return viewModel.items[index]
}, set: { newValue in
viewModel.items[index] = newValue
})) {
viewModel.items.remove(at: index)
}
}
Button("Add") {
viewModel.items.append("")
}
}
}
}
这是一个 SwiftUI 错误,例如与 类似的问题。
我无法完全解释导致崩溃的原因,但我已经能够重现该错误并且看起来在删除字段后,SwiftUI
仍在寻找所有 indices
当它试图访问已删除索引处的元素时,无法找到它,这会导致 index out of bounds
错误。
为了解决这个问题,我们可以编写一个条件语句来确保仅当 index
包含在 indices
.[=19= 的集合中时才搜索 element
]
FieldView(value: Binding<String>(get: {
if viewModel.items.indices.contains(index) {
return viewModel.items[index]
} else {
return ""
}
}, set: { newValue in
viewModel.items[index] = newValue
})) {
viewModel.items.remove(at: index)
}
上述解决方案解决了问题,因为它确保当元素数(items.count
)不大于index
时不会搜索该元素。
这正是我能够理解的,但幕后可能还发生了其他事情。
我正在尝试使用 ForEach
显示文本字段的动态列表。以下代码按预期工作:我可以 add/remove 文本字段,并且绑定正确。但是,当我在 ObservableObject
视图模型中移动 items
时,它不再工作并且崩溃并出现 index out of bounds
错误。这是为什么?我怎样才能让它发挥作用?
struct ContentView: View {
@State var items = ["A", "B", "C"]
var body: some View {
VStack {
ForEach(items.indices, id: \.self) { index in
FieldView(value: Binding<String>(get: {
items[index]
}, set: { newValue in
items[index] = newValue
})) {
items.remove(at: index)
}
}
Button("Add") {
items.append("")
}
}
}
}
struct FieldView: View {
@Binding var value: String
let onDelete: () -> Void
var body: some View {
HStack {
TextField("item", text: $value)
Button(action: {
onDelete()
}, label: {
Image(systemName: "multiply")
})
}
}
}
我正在尝试使用的视图模型:
class ViewModel: Observable {
@Published var items: [String]
}
@ObservedObject var viewModel: ViewModel
我发现很多问题都涉及同一问题,但我无法解决我的问题。其中一些没有提到 TextField
,其他一些没有工作(不再?)。
非常感谢
通过检查 Binding
内的边界,您可以解决问题:
struct ContentView: View {
@ObservedObject var viewModel: ViewModel = ViewModel(items: ["A", "B", "C"])
var body: some View {
VStack {
ForEach(viewModel.items.indices, id: \.self) { index in
FieldView(value: Binding<String>(get: {
guard index < viewModel.items.count else { return "" } // <- HERE
return viewModel.items[index]
}, set: { newValue in
viewModel.items[index] = newValue
})) {
viewModel.items.remove(at: index)
}
}
Button("Add") {
viewModel.items.append("")
}
}
}
}
这是一个 SwiftUI 错误,例如与
我无法完全解释导致崩溃的原因,但我已经能够重现该错误并且看起来在删除字段后,SwiftUI
仍在寻找所有 indices
当它试图访问已删除索引处的元素时,无法找到它,这会导致 index out of bounds
错误。
为了解决这个问题,我们可以编写一个条件语句来确保仅当 index
包含在 indices
.[=19= 的集合中时才搜索 element
]
FieldView(value: Binding<String>(get: {
if viewModel.items.indices.contains(index) {
return viewModel.items[index]
} else {
return ""
}
}, set: { newValue in
viewModel.items[index] = newValue
})) {
viewModel.items.remove(at: index)
}
上述解决方案解决了问题,因为它确保当元素数(items.count
)不大于index
时不会搜索该元素。
这正是我能够理解的,但幕后可能还发生了其他事情。