[SOLVED] Why is this showing only the first input values for each record?

Issue

This Content is from Stack Overflow. Question asked by dano9258

I have a CoreData setup where it saves the SleepModel correctly with unique ID, and values. I’ve checked and the count of SleepModel records goes up with each button click so Im pretty sure CoreData is setup and its saving correctly. However, while it does add another list row to display data, it is only displaying the very first input (not whatever input you put for subsequent entries). Here is what I have for the log view and sleep row views:

struct LogView: View {
    
    @StateObject var coreDataViewModel = CoreDataViewModel()
    
    var body: some View {
        VStack {
            if !coreDataViewModel.savedRecords.isEmpty {
                List {
                    ForEach(coreDataViewModel.savedRecords, id: .id) { record in
                        SleepRow()
                    }
                } // end list
            } //end if
        }   // end Vstack
        .onAppear {
                coreDataViewModel.fetchRecords()
            }
    }  // end body view
} // end LogView view
struct SleepRow: View {
    
    @StateObject var coreDataViewModel = CoreDataViewModel()
    
    var body: some View {
        ForEach(coreDataViewModel.savedRecords, id: .id) { record in
            HStack {
                
                    VStack(alignment: .leading) {
                        Text("Sleep Results").bold()
                            .font(.system(size:14))
        // Display Hours Slept
                 
                            Text("(record.hoursSlept, specifier: "%.2f") Hours Slept")
                                .font(.system(size:11)).foregroundColor(.red)
                        
        // Display AHI
                        Text("(record.ahiReading, specifier: "%.2f") AHI")
                            .font(.system(size:11)).foregroundColor(.gray)

......AND IT KEEPS GOING WITH MORE VALUES BUT DON'T WANT TO BORE YOU



Solution

try this example code, where you have one source of truth, @StateObject var coreDataViewModel = CoreDataViewModel() in LogView, and pass the model around to SleepRow using .environmentObject(coreDataViewModel). Note you do not use coreDataViewModel in SleepRow, so you could just, not pass the model to it.

// for testing
struct SleepModel: Identifiable, Hashable {
        let id = UUID().uuidString // ID variable
        var hoursSlept: Double // Hours slept variable
}

// for testing
class CoreDataViewModel: ObservableObject {
    @Published var savedRecords: [SleepModel] = []
    
    func fetchRecords() {
        savedRecords = [SleepModel(hoursSlept: 1.1),
                        SleepModel(hoursSlept: 2.2),
                        SleepModel(hoursSlept: 3.3),
                        SleepModel(hoursSlept: 4.4)
        ]
    }
}

struct SleepRow: View {
    @EnvironmentObject var coreDataViewModel: CoreDataViewModel // <-- here, only if required
    @State var sleep: SleepModel // <-- here
    
    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text("Sleep Results").bold()
                    .font(.system(size:14))
                Text("\(sleep.hoursSlept, specifier: "%.2f") Hours Slept")
                    .font(.system(size:11)).foregroundColor(.red)
            }
        }
    }
}

struct LogView: View {
    @StateObject var coreDataViewModel = CoreDataViewModel()
    
    var body: some View {
        VStack {
                List {
                    ForEach(coreDataViewModel.savedRecords, id: \.id) { record in
                        SleepRow(sleep: record)
                    }
                } // end list
        }   // end Vstack
        .environmentObject(coreDataViewModel) // <-- here, only if required in SleepRow
        .onAppear {
                coreDataViewModel.fetchRecords()
            }
    }  // end body view
} // end LogView view


This Question was asked in StackOverflow by dano9258 and Answered by workingdog support Ukraine It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?