SwiftUI NavigationLink @Binding of an array element causes Fatal error: Index out of range
SwiftUI NavigationLink @Binding of an array element causes Fatal error: Index out of range
我有一个可观察对象,它是我唯一的真实来源:
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)
}
}
}
}
}
问题在这里:
struct CarView: View {
@Binding var c: Car
@ObservedObject var net: NetworkFetcher
var body: some View {
VStack {
TextField("car name :", text: $c.name)
Button(action: {
self.net.erase()
}) {
Text("erase")
}
Button(action: {
self.net.add()
}) {
Text("add")
}
}
}
}
如果我点击擦除按钮,主列表将变成一个空数组。但是应用程序崩溃了,我收到了这个错误:
致命错误:索引超出范围:文件/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.2.25.8/swift/stdlib/public/core/ContiguousArrayBuffer.swift,第 444 行
问题是:
- 为什么?
- 如何解决?
此致
哇!另一个问题的答案适用于此。参见:
因此您应该将 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] = [=10=] }
)
return CarView(c: isOn, net: self.net)
}
}
我有一个可观察对象,它是我唯一的真实来源:
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)
}
}
}
}
}
问题在这里:
struct CarView: View {
@Binding var c: Car
@ObservedObject var net: NetworkFetcher
var body: some View {
VStack {
TextField("car name :", text: $c.name)
Button(action: {
self.net.erase()
}) {
Text("erase")
}
Button(action: {
self.net.add()
}) {
Text("add")
}
}
}
}
如果我点击擦除按钮,主列表将变成一个空数组。但是应用程序崩溃了,我收到了这个错误:
致命错误:索引超出范围:文件/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.2.25.8/swift/stdlib/public/core/ContiguousArrayBuffer.swift,第 444 行
问题是:
- 为什么?
- 如何解决?
此致
哇!另一个问题的答案适用于此。参见:
因此您应该将 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] = [=10=] }
)
return CarView(c: isOn, net: self.net)
}
}