SwiftUI .onDelete throws Fatal Error: Index out of range

£可爱£侵袭症+ 提交于 2021-01-29 22:33:49

问题


I have list of Accounts that each of them has a detail page and they are connected through @Binding in the AccountDetailView. Current code work well, updates are fine. No problem at all. However when I added the onDelete modifier to the ForEach below and tried swipe to delete gesture in app, it crashes and says Fatal Error: Index out of range twice.

I made some search and learned that ForEach somehow does not get notified -or ignores it, idk much detail- and looks for the last index of the array. In the end, it can not find it and throws the error.

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)
        }
    }
}

With keeping id: \.self parameter in place it throws the error at the AppDelegate, when I try to remove the parameter, the app works fine but again onDelete it throws the same error at NavigationLink's row above.

Here is the AccountDetailView

struct AccountDetailView: View {

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

    var body: some View {
        ...
    }
}

Finally Account class conforms to Codable, NSObject, Indentifiable and some other class. I did not want to give all the code just because did not want make the question complicated and hard to examine. If requested, I will provide any part of the code. Thanks in advance.


回答1:


Found a solution. With respect to the this answer to a related question, it came clear. Apperantly, with using the .indices to fullfill ForEach makes onDelete not to work. Instead, going through directly Elements of an array and creating proxy Bindings is working.

To be it more clear here are the ContentView, DetailView and an extension for Binding to avoid cluttering view.

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

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

This way, both onDelete and publishing changes by directly updating the object inside detail view will work.



来源:https://stackoverflow.com/questions/61668606/swiftui-ondelete-throws-fatal-error-index-out-of-range

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!