SwiftUI + Core Data: unable to delete entity

Viewed 33

Here how this piece of code works:

  • ListTimerView shows a list of Timer entity stored using Core Data. In this view there is a (+) button on the toolbar.
  • Clicking on the (+) button a new empty Timer is created using current context newTimerToAdd = Timer(context: viewContext).
  • TimerEditView is called and an empty Entity is passed to the view using ObservedObject.
  • TimerEditView can edit the entity. In the toolbar there are two buttons, Save or Discard changed. If I click on Save everything goes right. The error occurs only if I click on Discard button.

The logic behind is:

  • Create a temporary entity
  • Pass the entity to an Edit view and then Save in current context or Discard it

Here the "complete" code, and at the end the error printed in the console.

//***************************************************************
// TimerListView
//***************************************************************

import SwiftUI
import CoreData


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

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Timer.id, ascending: true)],
        animation: .default)
    private var timers: FetchedResults<Timer>
    
    @State private var isPresentingSheet = false
    @State private var showFavoritesOnly = false
    @State private var sheetView: SheetView = .setting
    @State var newTimerToAdd: Timer = Timer()

    
    
    var body: some View {
        
        // Include NavigationLinkk into NavigationView, otherwise it will look disabled
        NavigationView{
            
            List {
                
                ForEach(timers) { timer in
                    NavigationLink(destination: TimerDetailView(timer: timer)) {
                        TimerCardView(timer: timer)
                    }
                }

                
                
            }
            .navigationTitle("Timer")
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button(action: {
                        
                        
                        newTimerToAdd = Timer(context: viewContext)
                        newTimerToAdd.id = UUID()
                        newTimerToAdd.name = "Timer name"
                        newTimerToAdd.secondsOn = 0
                        newTimerToAdd.secondsOff = 0
                        newTimerToAdd.rounds = 1
                        newTimerToAdd.cycles = 1
                        newTimerToAdd.secondsOffBetweenCycles = 0
                        newTimerToAdd.favourite = false
                        
                        
                        sheetView = .newTimer
                        isPresentingSheet = true
                        
                        
                    }) {
                        Label("New timer", systemImage: "plus")
                    }
                }
            }
            
            
            .sheet(isPresented: $isPresentingSheet) {
                if (sheetView == .newTimer) {
                    NavigationView {
                        TimerEditView(timer: newTimerToAdd)
                            .toolbar {

                                //*********************************************************
                                //Here where the error occurs. If I debug this piece of code, the error occurs after
                                //the last line of code. 
                                //*********************************************************                            
                                ToolbarItem(placement: .cancellationAction) {
                                    Button("Dismiss") {

                                        viewContext.delete(newTimerToAdd)
                                        
                                        do {
                                            try viewContext.save()
                                        } catch {
                                            // Replace this implementation with code to handle the error appropriately.
                                            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                                            viewContext.rollback()
                                            //print("Failed to save context \(nsError.localizedDescription)")
                                            
                                            let nsError = error as NSError
                                            fatalError("CAZZO Unresolved error \(nsError), \(nsError.userInfo)")
                                            
                                            
                                        }
                                        
                                        isPresentingSheet = false

                                    }
                                }
                                ToolbarItem(placement: .confirmationAction) {
                                    Button("Add") {
                                        
                                       
                                        do {
                                            try viewContext.save()
                                        } catch {
                                            // Replace this implementation with code to handle the error appropriately.
                                            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                                            let nsError = error as NSError
                                            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
                                        }
                                        
                                        //timers.append(newTimerToAdd)
                                        isPresentingSheet = false
                                        //newTimer = Timer()
                                    }
                                }
                            } // .toolbar
                    } // NavigationView
                } else {
                    NavigationView {
                        SettingsView()
                            .toolbar {
                                ToolbarItem(placement: .confirmationAction) {
                                    Button("Salva") {
                                        isPresentingSheet = false
                                    }
                                }
                            }
                    }
                }
            } //.sheet
             
        }

    }
}

//***************************************************************
// TimerEditView
//***************************************************************

import SwiftUI

struct TimerEditView: View {
    @ObservedObject var timer:Timer
    @State private var isPresentingEditView = false
    @State private var whichTimer:String = ""
    @State private var data:Int = 0
    
    var body: some View {
        
        Form {
            Section(header: Text("Timer Info")) {
                TextField("Name", text: Binding($timer.name)!)
                
                HStack {
                    Text("Preferito")
                    Spacer()
                    FavoriteButton(isSet: $timer.favourite)
                }
                
            }
            
            Section {
                HStack {
                    Text("Lavoro")
                    Spacer()
                    Button {
                        whichTimer = "workTimer"
                        data = Int(timer.secondsOn)
                        isPresentingEditView = true
                    }
                    label: {
                        Text(timer.labelSecondsOn)
                    }
                }
                HStack {
                    Text("Riposo")
                    Spacer()
                    Button {
                        whichTimer = "restTimer"
                        data = Int(timer.secondsOff)
                        isPresentingEditView = true
                    }
                    label: {
                        Text(timer.labelSecondsOff)
                    }
                }
                HStack {
                    Stepper("Round: \(timer.rounds)", value: $timer.rounds, in: 1...30)
                }
                
            }  header: {
                Text("Round")
            } footer: {
                Text("Un round è un allenamento seguito da un riposo")
            }
            
            Section {
                HStack {
                    Stepper("Cicli: \(timer.cycles)", value: $timer.cycles, in: 1...30)
                }
                HStack {
                    Text("Riposo tra cicli")
                    Spacer()
                    Button {
                        whichTimer = "restTimerBetweenCycles"
                        data = Int(timer.secondsOffBetweenCycles)
                        isPresentingEditView = true
                    }
                    label: {
                        Text(timer.labelSecondsOffBetweenCycles)
                    }
                }
            }
            header: {
                Text("Cicli")
            } footer: {
                Text("Un ciclo corrisponde ad un round")
            }
            
        }
        .sheet(isPresented: $isPresentingEditView) {
            
            NavigationView {
                ChangeTimerView(totalSeconds: $data)
                    .navigationTitle("Tempo")
                    .toolbar {
                        ToolbarItem(placement: .cancellationAction) {
                            Button("Cancel") {
                                isPresentingEditView = false
                            }
                        }
                        ToolbarItem(placement: .confirmationAction) {
                            Button("Done") {
                                switch whichTimer {
                                case "workTimer":
                                    timer.secondsOn = Int16(data)
                                case "restTimer":
                                    timer.secondsOff = Int16(data)
                                case "restTimerBetweenCycles":
                                    timer.secondsOffBetweenCycles = Int16(data)
                                default:
                                    timer.secondsOn = Int16(data)
                                }
                                isPresentingEditView = false
                            }
                        }
                    }
            }//NavigationView
        }//.sheet
        
    }
}

//***************************************************************
// Main App
//***************************************************************


import SwiftUI

@main
struct Advanced_TimerApp: App {
    let persistenceController = PersistenceController.shared
    
    var body: some Scene {
        WindowGroup {
            TimerListView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
                //.environmentObject(AdvancedTimer())
        }
    }
}

//***************************************************************
// Persistence (basically the default provided by Apple)
//***************************************************************

import CoreData

struct PersistenceController {
    static let shared = PersistenceController()

    static var preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
        
        for i in 0..<10 {
            let newTimerToAdd = Timer(context: viewContext)
            //let newTimerToAdd = Timer(id: UUID(), name: newTimer.name, secondsOn: newTimer.secondsOn, secondsOff: newTimer.secondsOff, rounds: newTimer.rounds, cycles: newTimer.cycles, secondsOffBetweenCycles: newTimer.secondsOffBetweenCycles, favourite: newTimer.favourite)
            newTimerToAdd.id = UUID()
            newTimerToAdd.name = "Timer \(i)"
            newTimerToAdd.secondsOn = 60
            newTimerToAdd.secondsOff = 30
            newTimerToAdd.rounds = 2
            newTimerToAdd.cycles = 1
            newTimerToAdd.secondsOffBetweenCycles = 0
            newTimerToAdd.favourite = (i % 2 == 0) ? true : false
        }
        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()

    let container: NSPersistentContainer

    init(inMemory: Bool = false) {
        container = NSPersistentContainer(name: "Model")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
    }
}



2022-09-06 21:01:01.498482+0200 Advanced Timer[53782:3631004] [error] error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'Timer'
CoreData: error: CoreData: error: Failed to call designated initializer on NSManagedObject class 'Timer' 

2022-09-06 21:01:01.500029+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI14_UIHostingViewGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.532761+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI14_UIHostingViewGVS_15ModifiedContentGVS_17_UnaryViewAdaptorVS_9EmptyView_GVS_18StyleContextWriterVS_14NoStyleContext___ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.535611+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI14_UIHostingViewGVS_15ModifiedContentGS1_VVS_22_VariadicView_Children7ElementVS_24NavigationColumnModifier_GVS_18StyleContextWriterVS_19SidebarStyleContext___ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.558195+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI16UIKitBarItemHostVS_11BarItemView_ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.576846+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI16UIKitBarItemHostVS_11BarItemView_ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.589925+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.600503+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.603573+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.606157+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:01.608962+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.097483+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.105100+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI14_UIHostingViewVS_7AnyView_ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.114845+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI14_UIHostingViewVVS_P10$109b5d55821BridgedNavigationView8RootView_ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.132879+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI16UIKitBarItemHostVS_11BarItemView_ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.134664+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI16UIKitBarItemHostVS_11BarItemView_ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.143203+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.150091+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.153836+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.155381+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.156777+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.163936+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.166516+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.168053+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.169055+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.170094+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.171122+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
2022-09-06 21:01:05.171991+0200 Advanced Timer[53782:3631004] [UIFocus] _TtGC7SwiftUI15CellHostingViewGVS_15ModifiedContentVS_14_ViewList_ViewVS_26CollectionViewCellModifier__ implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen.
sono qui
sono qui 2
2022-09-06 21:01:10.843201+0200 Advanced Timer[53782:3631004] [SystemGestureGate] <0x12c107010> Gesture: System gesture gate timed out.
0 Answers
Related