首页 > 解决方案 > SwiftUI:无法删除列表中的行

问题描述

我在 Xcode 中有一个小的 swiftUI 程序,它可以让我在一个列表中创建和删除用户,并使用步进器来计算用户的点数。

除非删除用户,否则一切正常(添加用户、重命名用户、步进计数)。

它抛出一个错误:

致命错误:索引超出范围:文件 /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.2.25.8/swift/stdlib/public/core/ContiguousArrayBuffer.swift,第 444 行 2020-05-23 12 :06:22.854920 + 0200计数器[21328:1125981]致命错误:索引超出范围:文件/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.2.25.8/swift/stdlib/public/core/ ContiguousArrayBuffer.swift,第 444 行

这是代码:

import SwiftUI

struct ContentView : View {
    @State var isEditing = false
    @State var stepperWerte = [3, 5, 7, 9]
    @State var editText = ["Player 1", "Player 2", "Player 3", "Player 4"]

    var startName = "new Player"
    var startLeben = 5

    var body: some View {
        NavigationView {
                List() { 
                    ForEach(0..<editText.count, id: \.self) {
                        spieler in HStack {
                            if self.editText.indices.contains(spieler) {
                            Stepper(value: self.$stepperWerte[spieler], in: -1...10, step: 1, label: {
                                TextField("", text: self.$editText[spieler], onEditingChanged: {_ in }, onCommit: {self.saveText(id: spieler, Text: self.editText[spieler])} )
                                .layoutPriority(1)
                                .fixedSize(horizontal: true, vertical: false)
                                Text("\(self.stepperWerte[spieler]) - \(spieler) - \(self.editText.count)")})
                            }
                        }
                    }
                    .onDelete(perform: spielerLoeschen)
                    .frame(width: nil, height: nil, alignment: .trailing)
                }
            .navigationBarTitle(Text("Nav_Title"))
            .navigationBarItems(leading: Button(action: { self.isEditing.toggle() }) { Text(isEditing ? "Done" : "Edit").frame(width: 85, height: 40, alignment: .leading) }, 
                                trailing: Button(action: spielerHinzufuegen, label: { Image(systemName: "plus") }) )
            .environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
        }
    }

    func spielerLoeschen(at offsets: IndexSet) {
        stepperWerte.remove(atOffsets: offsets)
        editText.remove(atOffsets: offsets)
    }
    func spielerHinzufuegen() {
        stepperWerte.append(startLeben)
        editText.append(startName)
    }
    func saveText(id: Int, Text: String) {
        editText[id] = Text
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

(忽略HStack后面的“if”,它没有实际效果,最后文本中的那些额外打印显示索引和总数)

如果我转储数组(stepperWerte 和 editText),它们会以正确的方式删除 -> 选择删除的播放器将从两个数组中正确删除。

如果我改变

TextField("", text: self.$editText[spieler]

TextField("", text: self.$editText[0]

它可以工作(除非它自然地显示所有行中的第一个玩家,并且在删除所有玩家(=行)后我得到了同样的错误)

任何帮助都会很棒-谢谢!

标签: listswiftui

解决方案


根据@Asperi,我已将代码更改为以下内容:导入 SwiftUI

struct BetterTextField : 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
        })
        .layoutPriority(1)
        .fixedSize(horizontal: true, vertical: false)
    }
}

struct ContentView : View {
    @State var isEditing = false
    @State var stepperWerte = [3, 5, 7, 9]
    @State var editText = ["Player 1", "Player 2", "Player 3", "Player 4"]

    var startName = "new Player"
    var startLeben = 5

    var body: some View {
        NavigationView {
                List() { 
                    ForEach(0..<editText.count, id: \.self) {
                        spieler in HStack {
                            if self.editText.indices.contains(spieler) {
                            Stepper(value: self.$stepperWerte[spieler], in: -1...10, step: 1, label: {
                                BetterTextField(container: self.$editText, index: self.editText.firstIndex(of: self.editText[spieler])!, text: self.editText[spieler])
                                Text("\(self.stepperWerte[spieler]) - \(spieler) - \(self.editText.count)")})
                            }
                        }
                    }
                    .onDelete(perform: spielerLoeschen)
                    .frame(width: nil, height: nil, alignment: .trailing)
                }
            .navigationBarTitle(Text("Nav_Title"))
            .navigationBarItems(leading: Button(action: { self.isEditing.toggle() }) { Text(isEditing ? "Done" : "Edit").frame(width: 85, height: 40, alignment: .leading) }, 
                                trailing: Button(action: spielerHinzufuegen, label: { Image(systemName: "plus") }) )
            .environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
        }
    }

    func spielerLoeschen(at offsets: IndexSet) {
        stepperWerte.remove(atOffsets: offsets)
        editText.remove(atOffsets: offsets)
    }
    func spielerHinzufuegen() {
        stepperWerte.append(startLeben)
        editText.append(startName)
    }
    func saveText(id: Int, Text: String) {
        editText[id] = Text
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

...它的工作原理 - 谢谢!

但是:这是 SwiftUI 中的错误还是故意的?


推荐阅读