SwiftUI Nested ForEach вызывает фатальную ошибку: каждый элемент макета может возникнуть только один раз

Я пытаюсь создать представление LazyVGrid для отображения содержимого объектов в массиве с помощью вложенных операторов ForEach. Код вызывает сбой приложения с сообщением "Неустранимая ошибка: каждый элемент макета может возникнуть только один раз".

Каждый объект содержит массив значений, которые необходимо отобразить в виде строки в сетке. Строка состоит из ячейки со строкой артикула объекта, за которой следует количество ячеек с целыми числами из массива объекта.

Я решил использовать класс вместо структуры, потому что мне нужно обновить массив внутри класса.

Это класс для объектов в массиве.

class RoomPickupData: Identifiable {
    let id = UUID()
    var sku: String = ""
    // Array of counts for sku on a particular date
    var roomsForDate: [Date: Int] = [:]
}

В коде первый ForEach используется для размещения информации заголовка в первой строке сетки.

Следующий ForEach и вложенный в него ForEach вызывают ошибку.

Внешний ForEach выполняет итерацию по массиву объектов, поэтому я могу создать строку в сетке для каждого объекта. Каждая строка состоит из строки, за которой следуют значения из массива roomsForDate. Размер массива roomsForDate не фиксирован.

Если я закомментирую вложенный ForEach, код будет выполнен, но с ним я получу фатальную ошибку.

Если я закомментирую Text(roomData.value.description) так, чтобы во внутреннем ForEach было отмечено, код тоже работает нормально. Если я заменю Text(roomData.value.description) на Text(""), приложение выйдет из строя.

Вложенность ForEach кажется лучшим способом создания представления сетки из двухмерного массива или массива объектов, каждый из которых содержит массив.

Я нашел другие сообщения, показывающие, что вложенные операторы ForEach можно использовать в SwiftUI.

Вот код. Ваша помощь в решении этой проблемы приветствуется.

struct RoomTableView: View {
    @ObservedObject var checkfrontVM: CheckFrontVM
    let dateFormatter = DateFormatter()
    
    init(checkfrontVM: CheckFrontVM) {
        self.checkfrontVM = checkfrontVM
        dateFormatter.dateFormat = "MM/dd/yyyy"
    }
    
    func initColumns() -> [GridItem] {
        var columns: [GridItem]
        var columnCount = 0
        
        if self.checkfrontVM.roomPickupDataArray.first != nil {
            columnCount = self.checkfrontVM.roomPickupDataArray.first!.roomsForDate.count
        } else {
            return []
        }
        columns = [GridItem(.flexible(minimum: 100))] + Array(repeating: .init(.flexible(minimum: 100)), count: columnCount)
        return columns
    }
    
    var body: some View {
        if self.checkfrontVM.roomPickupDataArray.first != nil {
            ScrollView([.horizontal, .vertical]) {
                
                LazyVGrid(columns: initColumns()) {
                    Text("Blank")
                    ForEach(self.checkfrontVM.roomPickupDataArray.first!.roomsForDate.sorted(by: {
                        $0 < $1
                    }), id: \.key) { roomData in
                        Text(dateFormatter.string(from: roomData.key))
                    }
                    
                    ForEach(self.checkfrontVM.roomPickupDataArray) { roomPickupData in
                        Group {
                            Text(roomPickupData.sku)
                                .frame(width: 80, alignment: .leading)
                                .background(roomTypeColor[roomPickupData.sku])
                                .border(/*@START_MENU_TOKEN@*/Color.black/*@END_MENU_TOKEN@*/)
                            ForEach(roomPickupData.roomsForDate.sorted(by: { $0.key < $1.key}), id: \.key) { roomData in
                                Text(roomData.value.description)
                            }
                        }
                    }
                }
                .frame(height: 600, alignment: .topLeading)
            }
            .padding(.all, 10)
        }
    }
}

2 ответа

Каждому элементу в ForEach нужен уникальный идентификатор. Код можно изменить, добавив следующую строку в текстовое представление во внутреннем ForEach, чтобы присвоить уникальный идентификатор.

.id ("тело (roomPickupData.id)-(roomData.key)")

ForEach(self.checkfrontVM.roomPickupDataArray) { roomPickupData in
    Group {
        Text(roomPickupData.sku)
        .frame(width: 80, alignment: .leading)
           .background(roomTypeColor[roomPickupData.sku])
           .border(Color.black)
        ForEach(roomPickupData.roomsForDate.sorted(by: { $0.key < $1.key}), id: \.key) { roomData in
          Text(roomData.value.description)
            .id("body\(roomPickupData.id)-\(roomData.key)") //<-
          }
        }
       }

Я столкнулся с той же ошибкой внутри ForEach внутри LazyVStack Я решил это, добавив UUID() идентификатор самого внутреннего View, например

      .id(UUID)

Вот пример: LazyVStack {

         ForEach(vmHome.allCategories, id: \.self) { category in
             VStack {
                   HStack {
                        Text(category)
                                    .font(.title3)
                                    .bold()
                                    .padding(10)
                                Spacer()
                            }
                            ScrollView(.horizontal) {
                                LazyHStack{
                                    ForEach(vmHome.getMovies(forCat: category), id: \.self.id) {
                                        movie in
                                        StandardHomeMovieView(movie: movie)
                                       .id(UUID())
                                   }
                                }
                                
                            }
                    }
                }
            
Другие вопросы по тегам