为了在SwiftUI上使用TextField实现可编辑的高音,我曾经ForEach(0..<items.count)处理过索引。
ForEach(0..<items.count)
import SwiftUI struct DummyView: View { @State var animals: [String] = ["🐶", "🐱"] var body: some View { List { EditButton() ForEach(0..<animals.count) { i in TextField("", text: self.$animals[i]) } } } }
但是,如果将表更改为可删除,则会出现问题。
import SwiftUI struct DummyView: View { @State var animals: [String] = ["🐶", "🐱"] var body: some View { List { EditButton() ForEach(0..<animals.count) { i in TextField("", text: self.$animals[i]) // Thread 1: Fatal error: Index out of range } .onDelete { indexSet in self.animals.remove(atOffsets: indexSet) // Delete "🐶" from animals } } } }
Thread 1: Fatal error: Index out of range 删除项目时
Thread 1: Fatal error: Index out of range
animals已从动物中删除,即使animal.count为1,ForEach循环也似乎运行了两次。
(lldb) po animals.count 1 (lldb) po animals ▿ 1 element - 0 : "🐱"
请给我有关Foreach和TextField组合的建议。 谢谢。
好的,原因是在使用过的ForEach构造函数的文档中(您看到范围是恒定的,因此ForEach会获取初始范围并保存它):
/// Creates an instance that computes views on demand over a *constant* /// range. /// /// This instance only reads the initial value of `data` and so it does not /// need to identify views across updates. /// /// To compute views on demand over a dynamic range use /// `ForEach(_:id:content:)`. public init(_ data: Range<Int>, @ViewBuilder content: @escaping (Int) -> Content)
因此解决方案将是提供动态容器。您可以在下面找到可能方法的演示。
完整的模块代码
import SwiftUI struct DummyView: View { @State var animals: [String] = ["🐶", "🐱"] var body: some View { VStack { HStack { EditButton() Button(action: { self.animals.append("Animal \(self.animals.count + 1)") }, label: {Text("Add")}) } List { ForEach(animals, id: \.self) { item in EditorView(container: self.$animals, index: self.animals.firstIndex(of: item)!, text: item) } .onDelete { indexSet in self.animals.remove(atOffsets: indexSet) // Delete "🐶" from animals } } } } } struct EditorView : View { var container: Binding<[String]> var index: Int @State var text: String var body: some View { TextField("", text: self.$text, onCommit: { self.container.wrappedValue[self.index] = self.text }) } } struct TestForEachCapture_Previews: PreviewProvider { static var previews: some View { DummyView() } }