【问题标题】:SwiftUI Nested ForEach causes Fatal error: each layout item may only occur onceSwiftUI Nested ForEach 导致致命错误:每个布局项可能只出现一次
【发布时间】:2020-12-16 19:37:46
【问题描述】:

我正在尝试创建一个 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("") 替换 Text(roomData.value.description) 应用程序崩溃。

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

【问题讨论】:

  • 这段代码不可测试,你会准备最小可重现的例子吗?

标签: swiftui swift5 ios14


【解决方案1】:

我在 ForEach 内的 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())
                                   }
                                }
                                
                            }
                    }
                }
            

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多