Date attribute syncing across core data objects

I have been creating an app, and when I save the core data, I give two attributes, they are String and Date types. For some reason, the date attribute syncs across all the objects I save, while the time attribute is just fine. ContentView code is:

import Foundation
import SwiftUI
import CoreData

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(entity: Time.entity(), sortDescriptors: [])
    private var times: FetchedResults<Time>
...    
    var body: some View {
        VStack{
            Text("Cube App")
                .font(.largeTitle)
                .fontWeight(.bold)
                .padding(.top, 4.0)
            Text(scrambles.randomElement()!)
                .font(.title)
                .fontWeight(.semibold)
                .multilineTextAlignment(.center)
                .padding([.top, .leading, .trailing])
            if start{
                Stopwatch(progressTime: $elapsedTime, isRunning: $timerRunning)
                    .padding(.top)
                    .fontWeight(.bold)
                    .onAppear{
                        timerRunning = true
                        toggleStartStop()
                    }
            }
                
            Button(startstop){
                toggleStart()
                if start == false{
                    saveTime = elapsedTime
                    elapsedTime = 0
                    timerRunning = false
                    stopTime()
                    toggleStartStop()
                }
            }
            .fontWeight(.bold)
            .font(.system(size: 30))
            .padding(.top, 30)
            Spacer()
        }
    }
    
    private func stopTime(){
        timerRunning = false
        print(saveTime)
        addTime()
    }
    
    private func addTime(){
        withAnimation{
            timeMinutes = saveTime / 6000
            timeSeconds = (saveTime % 6000) / 100
            timeMilliseconds = saveTime % 100
            let time = Time(context: viewContext)
            let date = Date()
            if timeMinutes == 0{
                if timeMilliseconds < 10{
                    time.time = "\(timeSeconds).0\(timeMilliseconds)"
                }else{
                    time.time = "\(timeSeconds).\(timeMilliseconds)"
                }
            }else if timeMilliseconds < 10{
                if timeSeconds < 10{
                    time.time = "\(timeMinutes):0\(timeSeconds).0\(timeMilliseconds)"
                }else{
                    time.time = "\(timeMinutes):\(timeSeconds).0\(timeMilliseconds)"
                }
            }else{
                if timeSeconds < 10{
                    time.time = "\(timeMinutes):0\(timeSeconds).\(timeMilliseconds)"
                }else{
                    time.time = "\(timeMinutes):\(timeSeconds).\(timeMilliseconds)"
                }
            }
            time.date = date
            
            saveContext()
        }
    }
    
    private func saveContext(){
        do {
            try viewContext.save()
        } catch {
            let error = error as NSError
            print(error)
            fatalError(error as! String)
        }
    }
    
    private func toggleStart(){
        if start{
            start = false
        }else{
            start = true
        }
    }
...
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let persistenceController = PersistenceController.shared
        ContentView().environment(\.managedObjectContext, persistenceController.container.viewContext)
    }
}

I also have another view to display all of the saved objects in a list, the code is:

import SwiftUI
import CoreData

struct timeListView: View {
    
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(entity: Time.entity(), sortDescriptors: [])
    private var times: FetchedResults<Time>
    
    @State var formattedTime: String = ""
    // format date and display
    var body: some View {
        VStack{
            Text("Times")
                .font(.largeTitle)
                .fontWeight(.bold)
                .multilineTextAlignment(.center)
                .padding(.top, 4.0)
            List{
                ForEach(times) {time in
                    HStack{
                        Text(time.time ?? "Not found")
                            .onAppear{
                                getDate(time: time)
                            }
                        Spacer()
                        Text(formattedTime)
                    }
                }
                .onDelete(perform: deleteTime)
            }
        }
    }
    
    private func getDate(time: Time){
        let date = time.date!
        let calendar = Calendar.current
        let hour = calendar.component(.hour, from: date)
        let minute = calendar.component(.minute, from: date)
        let second = calendar.component(.second, from: date)
        let timeToFormatComponents = DateComponents(calendar: calendar,
                                          year: calendar.component(.year, from: date),
                                          month: calendar.component(.month, from: date),
                                          day: calendar.component(.day, from: date),
                                          hour: hour,
                                          minute: minute,
                                          second: second
        )
        let timeToFormat = timeToFormatComponents.date!
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .medium
        formattedTime = formatter.string(from: timeToFormat)
        //UNSYNC THE DATES
    }
    
    private func deleteTime(offsets: IndexSet){
        withAnimation{
            offsets.map { times[$0] }.forEach(viewContext.delete)
            saveContext()
        }
    }
    
    private func saveContext(){
        do {
            try viewContext.save()
        } catch {
            let error = error as NSError
            print(error)
            fatalError(error as! String)
        }
    }
}

struct timeListView_Previews: PreviewProvider {
    static var previews: some View {
        let persistenceController = PersistenceController.shared
        timeListView().environment(\.managedObjectContext, persistenceController.container.viewContext)
    }
}

Could somebody please tell me how to unsync the dates and make sure they are separate? I will attach images of what is happening below:

I save the first one:

And then I save the second one:

Answered by thackerdynasty in 756041022

I tried this, but it looks like it immediately crashes when I open the view. No errors are given by swift either, just "Preview Crashed". When I build this and run in the simulator, it says "Index out of range." I looked at the code but cannot see what is happening, could you help?

Problem probably comes from the way formattedTime is computed:

            List{
                ForEach(times) {time in
                    HStack{
                        Text(time.time ?? "Not found")
                            .onAppear{
                                getDate(time: time)
                            }
                        Spacer()
                        Text(formattedTime)
                    }
                }

The formattedTime you get is the last of the ForEach loop.

So I would try to change

    @State var formattedTime: String = ""

by an array:

    @State var formattedTimes: [String] = []

Replace ForEach by

                ForEach(Array(times.enumerated()), id: \.offset) { (index, time) in
                    HStack{
                        Text(time.time ?? "Not found")
                        Spacer()
                        Text(formattedTimes[index])
                    }
  • And have onAppear to apply to the List, not each Text.
  • Then in .onAppear, append the formattedTime to formattedTimes
Accepted Answer

I tried this, but it looks like it immediately crashes when I open the view. No errors are given by swift either, just "Preview Crashed". When I build this and run in the simulator, it says "Index out of range." I looked at the code but cannot see what is happening, could you help?

You marked your answer as correct, which means you have solved the issue. So don't expect much help on this thread.

So open a new thread.

PS: have you initialized formattedTimes in .onAppear ?

Date attribute syncing across core data objects
 
 
Q