SwiftUI .onDelete выдает фатальную ошибку: индекс вне допустимого диапазона - PullRequest
0 голосов
/ 08 мая 2020

У меня есть список Account s, каждый из которых имеет страницу с подробностями, и они подключены через @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 класс соответствует Codable, NSObject, Indentifiable и некоторым другим классам. Я не хотел приводить весь код только потому, что не хотел усложнять вопрос и усложнять его рассмотрение. Если потребуется, я предоставлю любую часть кода. Заранее спасибо.

1 Ответ

0 голосов
/ 14 мая 2020

Нашел решение. Что касается этого ответа на связанный вопрос, это стало ясным. По-видимому, при использовании .indices для заполнения ForEach onDelete не работает. Вместо этого работает прямой переход 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 и публикация изменений путем прямого обновления объекта в подробном представлении будет работать.

...