首页 > 解决方案 > SwiftUI .onDelete 抛出致命错误:索引超出范围

问题描述

我有一个 s 列表,它们每个都有一个详细信息页面,Account并且它们通过@Binding. AccountDetailView当前代码运行良好,更新很好。完全没有问题。但是,当我将onDelete修饰符添加到ForEach下面并在应用程序中尝试swipe to delete手势时,它会崩溃并说Fatal Error: Index out of range两次。

我进行了一些搜索并了解到ForEach不知何故没有得到通知 - 或者忽略它,idk 很多细节 - 并寻找数组的最后一个索引。最后,它找不到它并抛出错误。

List {
    Section(header: Text(String.empty), footer: Text(Strings.SectionFooters.accountListFooter.value)) {
        ForEach(self.accountsModel.accounts.indices, id:\.self) { idx in
            NavigationLink(destination: AccountDetailView(account: self.$accountsModel.accounts[idx])) {
                AccountRow(account: self.$accountsModel.accounts[idx])
            }
        }.onDelete { (set) in
            self.accountsModel.accounts.remove(atOffsets: set)
        }
    }
}

id: \.self参数保持在适当位置时,它会在 ' 处引发错误AppDelegate,当我尝试删除参数时,应用程序可以正常工作,但它再次在上面的行处onDelete引发相同的错误。NavigationLink

这里是AccountDetailView

struct AccountDetailView: View {

    @EnvironmentObject var accountsModel: AccountsViewModel
    @Binding var account: Account
    @State var isEditing: Bool = false

    var body: some View {
        ...
    }
}

finallyAccount类符合Codable,NSObjectIndentifiable其他一些类。我不想仅仅因为不想让问题变得复杂且难以检查而给出所有代码。如果需要,我将提供代码的任何部分。提前致谢。

标签: swiftswiftuiswiftui-listswiftui-navigationlink

解决方案


找到了解决方案。关于对相关问题的这个答案,它很清楚。显然,使用.indicesto ForEachfullfillonDelete无法正常工作。相反,直接Elements通过数组并创建代理Bindings是有效的。

这里更清楚的是ContentView,和一个用于避免混乱视图DetailView的扩展。Binding

ContentView

struct ContentView: View {

    @EnvironmentObject var store: DataStore

    var body: some View {
        NavigationView {
            List {
                ForEach(self.store.data, id: \.id /*with or without id*/) { (data) in
                    NavigationLink(destination: DetailView(data: /*created custom initializer*/ Binding(from: data))) {
                        Text(data.name)
                    }
                }.onDelete { (set) in
                    self.store.data.remove(atOffsets: set)
                }
            }.navigationBarTitle("List")
        }
    }
}

DetailView

struct DetailView: View {

    @Binding var data: MyData

    var body: some View {
        List {
            TextField("name", text: self.$data.name)
        }
        .navigationBarTitle(self.data.name)
        .listStyle(GroupedListStyle())
    }
}

Binding扩大

extension Binding where Value: MyData {
    init(from data: MyData) {
        self.init(get: {
            data as! Value
        }) {
            dataStore.data[dataStore.data.firstIndex(of: data)!] = $0
        }
    }
}

这样,onDelete通过直接更新详细视图中的对象来发布更改和发布更改都将起作用。


推荐阅读