数组元素的SwiftUI NavigationLink @Binding导致致命错误:索引超出范围

时间:2020-07-24 11:34:02

标签: swift swiftui-navigationlink swiftui environmentobject

我有一个可观察的物体,这是我独特的真理来源:

local_bind_port

这是车:

class NetworkFetcher: ObservableObject {
    @Published var list: [Car] = [Car(id: UUID().uuidString, name: "Tesla"), Car(id: UUID().uuidString, name: "BMW")]

    func erase() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0) {
            self.list = []
        }
    }

    func add() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0) {
            self.list = [Car(id: UUID().uuidString, name: "Tesla S"), Car(id: UUID().uuidString, name: "BMW M3")]
        }
    }
}

在这里进行擦除和添加(编辑列表的功能),一切正常:

struct Car: Identifiable, Hashable {
    var id: String
    var name: String
}

问题在这里:

struct ContentView: View {
    @ObservedObject var net: NetworkFetcher = NetworkFetcher()

    var body: some View {
        NavigationView {
            VStack {
                ListView(liste: self.$net.list, net: self.net)
                Button(action: {
                    self.net.erase()
                }) {
                    Text("erase")
                }
                Button(action: {
                    self.net.add()
                }) {
                    Text("add")
                }
            }
        }
    }
}

struct ListView: View {
    @Binding var liste: [Car]
    @ObservedObject var net: NetworkFetcher

    var body: some View {
        List {
            ForEach(liste.indices, id: \.self) { i in
                NavigationLink(destination: CarView(c: self.$liste[i], net: self.net)) {
                    Text(self.liste[i].name)
                }
            }
        }
    }
}

如果单击“擦除”按钮,则主列表将更改为空数组。但是该应用程序崩溃了,并且出现了这个错误:

致命错误:索引超出范围:文件/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.2.25.8/swift/stdlib/public/core/ContiguousArrayBuffer。迅速,第444行

问题是:

  1. 为什么?
  2. 如何解决?

真诚的

1 个答案:

答案 0 :(得分:1)

哇!另一个问题有一个适用于此的答案。参见:https://stackoverflow.com/a/63080022

所以您应该使用:

更改ListView。
struct ListView: View {
    @Binding var liste: [Car]
    @ObservedObject var net: NetworkFetcher

    var body: some View {
        List {
            ForEach(liste.indices, id: \.self) { i in
                NavigationLink(destination: self.row(for: i)) {
                    Text(self.liste[i].name)
                }
            }
        }
    }

    private func row(for idx: Int) -> some View {
        let isOn = Binding(
            get: {
                // safe getter with bounds validation
            idx < self.liste.count ? self.liste[idx] : Car(id: UUID().uuidString, name: "EMPTY")
        },
            set: { self.liste[idx] = $0 }
        )
        return CarView(c: isOn, net: self.net)
    }
}