首页 > 解决方案 > SwiftUI - ForEach 内两个不同子视图的数据不一致

问题描述

我正在构建一个应用程序来制作图表并计算一些基本的东西。在主屏幕上,我在 List 中有一个 ForEach 循环,显示已保存的图表。在列表中输入 NavigationLink 时,目标视图与显示的标签不对应(下面的视频)。

我不得不使用自定义 ForEach 扩展来处理绑定https://www.swiftbysundell.com/articles/bindable-swiftui-list-elements/(Apple 宣布在 iOS 15 上 ForEach 将接受绑定,但我正在开发适用于 iOS 14)。

列表的代码:

List{
    ForEach($chartData.calibrations) { index, data in
        VStack{
            NavigationLink(
                destination: DetailedChartView(index: index, currentData: data, isDetailShown: $detailVisible),
                isActive: $detailVisible,
                label: {
                    SavedListItem(index: index, savedData: self.chartData.calibrations[index])
                })
                .navigationBarHidden(true)
        }
    }.onDelete(perform: removeRows)
}.id(UUID())
.listStyle(PlainListStyle())

标签的代码 (SavedListItem)

struct SavedListItem: View {
    
    var index: Int
    
    var data: ChartDataObject
    
    var formattedSlope = ""
    
    var formattedOrigin = ""
    
    var formattedCoef = ""
    
    init(index: Int, savedData: ChartDataObject) {
        
        self.data = savedData
        self.index = index
        
        self.formattedSlope = String(format: "%.2f", data.slope)
        self.formattedOrigin = String(format: "%.2f", abs(data.origin))
        self.formattedCoef = String(format: "%.3f", data.regressionCoef)
    }

    
    var body: some View {
        
        HStack {
            Text("\(index + 1)").bold()
            VStack(alignment: .leading,spacing: 10) {
                Text("\(data.name)").font(.title3)
                Text("\(formatDate(data.date))")
            }.padding()
            Spacer()
            if data.origin > 0 {
                VStack {
                    VStack {
                        Text("y = \(self.formattedSlope)x + \(formattedOrigin)")
                        Spacer().frame(height: 10)
                        Text("R2 = \(formattedCoef)")
                    }
                }
            }
            else if data.origin == 0 {
                VStack {
                    VStack {
                        Text("y = \(formattedSlope)x")
                        Spacer().frame(height: 10)
                        Text("R2 = \(formattedCoef)")
                    }
                }
            }
            else if data.origin < 0 {
                VStack {
                    VStack {
                        Text("y = \(formattedSlope)x - \(formattedOrigin)")
                        Spacer().frame(height: 10)
                        Text("R2 = \(formattedCoef)")
                    }
                }
            }
            else {
                Text("There was an error")
            }
        }
        .padding()
    }
    
    
    private func formatDate(_ date: Date) -> String {
        
        let dateFormatter = DateFormatter()
        
        dateFormatter.dateFormat = "dd-MM-yyyy"
        let dateString = dateFormatter.string(from: date)
        
        return dateString
    }
    
}

以及DetailedChartView的代码:

struct DetailedChartView: View {
    
    @EnvironmentObject var calibrationsController: SavedCalibrationsController
    
    var index: Int
    
    @Binding var currentData: ChartDataObject
    
    var copyData: ChartDataObject {
        return currentData
    }
            
    @State var isEditing: Bool = false
    
    @Binding var isDetailShown: Bool
    
    var body: some View {
        NavigationView{
            VStack(spacing: 10) {
                Text("y = \(currentData.origin) + \(currentData.slope)x")
                Text("Slope: \(currentData.slope)")
                Text("Origin: \(currentData.origin)")
                Text("R2: \(currentData.regressionCoef)")
                
                Divider()
                
                RegressionChart(data: currentData).frame(height: 500)
            }.navigationBarHidden(true)
        }
        .navigationBarTitle(currentData.name)
        .toolbar(content: {
            Button(action: {
                self.isEditing = true
            }, label: {
                Text("Edit")
            })
        })
        .sheet(isPresented: $isEditing, onDismiss: {
            currentData = copyData
            calibrationsController.saveData()
            isEditing = false
            isDetailShown = false
        }, content: {
            EditView(calibrationsController: calibrationsController, editVisible: $isEditing, isDetailShown: $isDetailShown, index: index, data: $currentData).environmentObject(calibrationsController)
        })
    }
}

当只有一项时,列表按预期运行。

动图

这个问题让我发疯:如果我使用列表(没有 ForEach),一切都会按预期工作,但我无法更改 ForEach,因为我失去了 .onDelete() 功能,并删除了详细视图中的项目(其中有一个编辑按钮),给我一个超出范围错误的索引(另一个故事......)。

对不起,很长的帖子!

编辑:最小的可复制示例

https://drive.google.com/file/d/1WN_tGR_kVNVNqEOW054d6kMBlq8HGkF5/view?usp=sharing

标签: iosswiftxcodeswiftui

解决方案


消除

isActive: $detailVisible,

在 MainList NavigationLink 中。


推荐阅读