SwiftUI嵌套的ForEach会导致致命错误:每个布局项目只能出现一次

问题描述

我正在尝试创建一个LazyVGrid视图,以使用嵌套的ForEach语句显示数组中对象的内容。该代码导致应用程序崩溃,并显示消息“致命错误:每个布局项目只能出现一次”。

每个对象都包含一个值数组,这些值需要在网格中显示为一行。该行包含具有对象sku字符串的单元格,然后是具有对象数组中整数的单元格。

我选择使用类而不是结构,因为我需要更新类中的数组。

这是数组中对象的类。

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

解决方法

ForEach中的每个项目都需要一个唯一的ID。可以通过在内部ForEach的“文本”视图中添加以下行来分配唯一ID,来修改代码:

.id("body\(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)") //<-
          }
        }
       }