Этот рвал мне волосы, надеюсь, кто-нибудь покажет мне, в чем я ошибаюсь.
Цель состоит в том, что мне нужно иметь возможность управлять динамическим списком элементов (т.е. список может увеличиваться или уменьшаться), где свойства каждого элемента могут быть скорректированы (отредактированы), а элементы связаны с данным родителем.
В сокращенном коде ниже я назвал элемент Cell, который принадлежит Row. Строка может иметь много ячеек, и каждая ячейка имеет количество, которое может быть изменено пользователем. Это сокращенная версия моего кода, которая, я надеюсь, делает маркировку отношений немного более ясной, но, что особенно важно, она дает мне ту же ошибку, которая:
Если количество ячеек меньше исходного количества (т.е. 3 или меньше в этом примере), тогда приложение вылетает с ошибкой «Индекс вне диапазона» всякий раз, когда закрывается представление. До этого момента ячейки можно было добавлять или удалять без каких-либо проблем, и я не получаю эту ошибку при изменении количества элементов ячеек. Я просмотрел все SO и различные блоги и не могу найти никого, кто сталкивался с этой конкретной проблемой - кажется, что большинство сообщений Index вне диапазона происходит при фактическом изменении списка, моя ошибка возникает только после того, как список сокращается и затем отклонен.
Я прикрепил пример кода ниже - вы сможете вырезать / вставить и попробовать.
PS. Я знаю, что calculateTotals () - это скетч; пожалуйста, не добавляйте буквы или знаки препинания к сумме - это просто для проверки корректности привязки :)
Ячейка
struct Cell: Identifiable {
var amount: String
var id = UUID()
init(_ amount: String = "0.00"){
self.amount = amount
}
}
Строка
class Row: ObservableObject {
@Published var cells: [Cell]
init(){
self.cells = [
Cell("10"),
Cell("15"),
Cell("20"),
Cell("25")]
}
}
ContentView
struct ContentView: View {
@State private var displayAmounts = false
var body: some View {
NavigationView {
Button(action: {
self.displayAmounts.toggle()
}) {
Text("View amounts")
}
}
.sheet(isPresented: self.$displayAmounts) {
CellSheet()
}
}
}
Таблица ячеек
struct CellSheet: View {
@ObservedObject var row: Row = Row()
private func deleteCell(at offsets: IndexSet) {
self.row.cells.remove(atOffsets: offsets)
}
private func calculateTotals() -> String {
var total = Double("0.00")!
for cell in self.row.cells {
if( "" != cell.amount ) {
total += Double(cell.amount)!
}
}
return String("\(total)")
}
var body: some View {
VStack{
List {
ForEach(row.cells.indices, id: \.self){ i in
CellItem(amount: self.$row.cells[i].amount)
}.onDelete(perform: deleteCell)
}
Button(action: {
self.row.cells.append(Cell())
}) {
Text("Add new cell")
}
Text(calculateTotals())
}
}
}
CellItem - здесь какая-то странность: если я заключу TextField в HStack, приложение сразу выйдет из строя при удалении ячейки - даже если общее количество ячеек больше исходного количества (4).
struct CellItem: View {
@Binding var amount: String
var body: some View {
// Uncomment HStack and deleting rows immediately causes index out of range.
// HStack {
TextField("Amount: ", text: $amount)
// }
}
}
Я действительно не понимаю, почему и как это происходит. Очевидно, Swift пытается получить доступ к несуществующему индексу (если я удалю привязку и просто выведу значение, проблем не возникнет), но я не понимаю, почему это может вызвать проблемы при закрытии представления. Я предполагаю, что Swift кое-что кеширует в памяти? Проблема с упаковкой HStack также является своеобразной.
В любом случае, я относительно новичок в Swift, поэтому, возможно, я упускаю из виду что-то очевидное. Для дополнительного контекста я использую XCode 11.4.1 и ориентируюсь на iOS 13.4.
Вы сможете перенести весь этот код прямо в новый проект, и он будет скомпилирован. Любая помощь будет с благодарностью получена :)