У меня сложная структура данных, в которой используются типы значений (структуры и перечисления), и я столкнулся с серьезными проблемами, связанными с работой c CRUD. В частности:
- Как лучше всего «повторно привязать» значение в ForEach для редактирования дочерним представлением
- Как удалить / удалить значение
Rebinding
Если у меня есть массив элементов как @State
или @Binding
, почему нет простого способа привязать каждый элемент к представлению? Например:
import SwiftUI
struct Item: Identifiable {
var id = UUID()
var name: String
}
struct ContentView: View {
@State var items: [Item]
var body: some View {
VStack {
ForEach(items, id: \.id) { item in
TextField("name", text: $item) // ? Cannot find '$item' in scope
}
}
}
}
Обходной путь
Я смог обойти это, представив вспомогательную функцию для поиска правильного индекса для элемента в al oop:
struct ContentView: View {
@State var items: [Item]
func index(of item: Item) -> Int {
items.firstIndex { $0.id == item.id } ?? -1
}
var body: some View {
VStack {
ForEach(items, id: \.id) { item in
TextField("name", text: $items[index(of: item)].name)
}
}
}
}
Однако это кажется неуклюжим и, возможно, опасным.
Удаление
Гораздо более серьезная проблема: как вы должны правильно удалить элемент? Это звучит как базовый c вопрос, но учтите следующее:
struct ContentView: View {
@State var items: [Item]
func index(of item: Item) -> Int {
items.firstIndex { $0.id == item.id } ?? -1
}
var body: some View {
VStack {
ForEach(items, id: \.id) { item in
TextField("name", text: $items[index(of: item)].name)
Button( action: {
items.remove(at: index(of: item))
}) {
Text("Delete")
}
}
}
}
}
Нажатие кнопки «Удалить» на первых нескольких элементах работает должным образом, но попытка Удалить последний элемент приводит к Fatal error: Index out of range
...
Мой конкретный вариант использования не соответствует списку, поэтому я не могу использовать там помощник по удалению.
Типы ссылок
Я знаю что ссылочные типы значительно упрощают эту задачу, особенно если они могут соответствовать @ObservableObject
. Однако у меня есть массивный, вложенный, уже существующий тип значения, который нелегко преобразовать в классы.
Любая помощь будет очень признательна!
Обновление: Предлагаемые решения
- Удаление элементов списка из списка SwiftUI : принятый ответ предлагает сложную настраиваемую оболочку привязки. Swift - мощный инструмент, поэтому многие проблемы можно решить с помощью продуманных обходных путей, но я не думаю, что для получения списка редактируемых элементов требуется сложное обходное решение.
- Пометить представления как «удаленные» с помощью State или частную переменную, а затем условно скройте их, чтобы избежать ошибок, выходящих за границы. Это может сработать, но похоже на взлом, и это должно выполняться фреймворком.