SwiftUI Nested ForEach 导致致命错误:每个布局项只能出现一次

tom*_*mmy 8 swift5 swiftui ios14

我正在尝试创建一个 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] = [:]
}
Run Code Online (Sandbox Code Playgroud)

在代码中,第一个 ForEach 用于将标题信息放在网格的第一行。

下一个 ForEach 和嵌套在其中的 ForEach 导致错误。

外部 ForEach 遍历对象数组,因此我可以在网格中为每个对象创建一行。每行包含一个字符串,后跟来自 roomsForDate 数组的值。roomsForDate 数组的大小不固定。

如果我注释掉嵌套的 ForEach 代码会执行,但我会收到致命错误。

如果我注释掉 Text(roomData.value.description) 以便在内部 ForEach 中有注释,则代码也运行良好。如果我用 Text("") 替换 Text(roomData.value.description) 应用程序崩溃。

ForEach 嵌套似乎是从二维数组或每个包含一个数组的对象数组完成生成网格视图的最佳方式。

我发现其他帖子表明可以在 SwiftUI 中使用嵌套的 ForEach 语句。

这是代码。感谢您对此问题的帮助。

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

Run Code Online (Sandbox Code Playgroud)

tom*_*mmy 13

中的每个项目都ForEach需要一个唯一的 ID。可以通过在内部的 Text 视图中添加以下行来修改代码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)") //<-
          }
        }
       }
Run Code Online (Sandbox Code Playgroud)