SwiftUI .onDelete引发致命错误:索引超出范围

时间:2020-05-07 22:11:31

标签: swift swiftui swiftui-list swiftui-navigationlink

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

我进行了一些搜索,发现ForEach不会以某种方式得到通知-或将其忽略,详细信息-并查找数组的最后一个索引。最后,它找不到它并引发错误。

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 {
        ...
    }
}

最后Account类符合CodableNSObjectIndentifiable和其他某个类。我不想给出所有代码,只是因为不想使问题复杂且难以检查。如果需要,我将提供代码的任何部分。预先感谢。

1 个答案:

答案 0 :(得分:0)

找到了解决方案。关于这个answer的相关问题,这一点很明确。适当地,使用.indices填充ForEach会使onDelete无法正常工作。相反,直接遍历数组的Elements并创建代理Bindings是可行的。

更清楚地说,这里是ContentViewDetailViewBinding的扩展名,以避免视图混乱。

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和通过直接更新详细信息视图内的对象来发布更改都将起作用。