Search code examples
swiftcore-dataswiftuiapple-watch

How to delete Core Data SwiftUI?


Sorry for the Dumb question, but I have been searching for the answer like two days and tried many ways of dealing with it.

My WatchOS app running on Core Data. There are 3 Views there:

  1. FirstView - a view with a button to Add a new Goal and a List of added Goals.
  2. AddGoalView - appears after pressing Add new Goal.
  3. RingView - a view with a with Goal Ring (similar to activity ring mechanics) and all the data presented.

So, I am trying to give the user an opportunity to delete a created Goal straight on the FirstView. After different iterations, I understood, that delete button is working inside the RingView, but not on the FirstView. Could you please give your thoughts towards this problem (and if you could, please give an .onDelete variant)?

Here is my FirstView Code:

struct FirstView: View {
@Environment(\.managedObjectContext) var context
@Environment(\.presentationMode) var presentationMode
@FetchRequest (
    entity:NewGoal.entity(),
    sortDescriptors:[NSSortDescriptor(keyPath: \NewGoal.dateAdded, ascending: false)],
    animation: .easeInOut )
var results:FetchedResults<NewGoal>
var body: some View {

    ScrollView{
        VStack{
        VStack(alignment: .leading){
    NavigationLink(
            destination: AddGoalView(),
            label: {
                Image(systemName: "plus")
                Text("Set Money Goal")
            })
        .frame(maxWidth: .infinity)
        .clipShape(RoundedRectangle(cornerRadius: 9))
        
         VStack(alignment: .leading){
            ForEach(results){ item in
                NavigationLink(
                    destination: RingView(goalItem: item, GTitle: item.goalTitle ?? "", Sum: item.neededSum, summarize: item.yourSum),
                    label: {

                        HStack{
                                Button(action: deleteGoal){
                                    Text("Delete") } //// < --- Here it is

                            Text(item.goalTitle ?? "")
                            Text("$\(item.yourSum, specifier: "%.f")")
                            Text("/ $\(item.neededSum, specifier: "%.f")")
                        }
                    })  .contentShape(Rectangle())
                        .clipShape(RoundedRectangle(cornerRadius: 9))
                   }
               }
            }
     }
   }
 }
    /////MY DELETE FUNC
  private func deleteGoal(){
        let goal = NewGoal (context: context)
        context.delete(goal)
        do{
            try context.save()
            presentationMode.wrappedValue.dismiss()
        } catch let err{
            print(err.localizedDescription)
            }
    }
    }

Here is my RingView Code (where everything is working):

struct RingView: View {
@State private var isFocused = false
@State private var isFocusedSum = false
@State private var name: String = ""
@State var dayindex = 0
@State private var yournewSum:Double = 0.0
var goalItem: NewGoal?
var GTitle:String
var Sum:Double
var summarize:Double
var allNewSum:Double = 0.0

@Environment(\.managedObjectContext) var context
@Environment(\.presentationMode) var presentationMode

@FetchRequest var results: FetchedResults<NewGoal>
init(goalItem: NewGoal? = nil, GTitle: String, Sum: Double, summarize: Double, allNewSum: Double){
self.GTitle = GTitle
self.Sum = Sum
self.goalItem = goalItem
self.summarize = summarize
self.allNewSum = allNewSum
    
let predicate = NSPredicate(format:"goalTitle == %@", GTitle)
self._results=FetchRequest(
    entity: NewGoal.entity(),
    sortDescriptors: [NSSortDescriptor(keyPath: \NewGoal.dateAdded, ascending: false)],
    predicate: predicate,
    animation: .easeInOut
                           )
}

var body: some View {
    NavigationView{
    ForEach(results) { item in
    ZStack{
        RingShape()
            .stroke(style: StrokeStyle(lineWidth: 11, lineCap: .round))
                            .fill(AngularGradient(gradient: Gradient(colors: [.red, .pink, .red]), center: .center))
                            .opacity(0.35)
        RingShape(percent:(((yournewSum + summarize)/Sum*100)+0.1), startAngle: -90, drawnClockwise: false) ///FG Ring SUM
            .stroke(style: StrokeStyle(lineWidth: 11, lineCap: .round))
                            .fill(AngularGradient(gradient: Gradient(colors: [.red, .pink, .red]), center: .center))
        
        RingShape() ///BG Ring Date
            .stroke(style: StrokeStyle(lineWidth: 4, lineCap: .round))
                            .fill(Color.yellow)
                            .opacity(0.35)
                            .frame(width: 145, height: 145)
        RingShape(percent: (Double((item.pickedValueDateN - item.pickedValueDateN1)*100) / (Double(item.pickedValueDateN) + 1) + 0.1), startAngle: -90, drawnClockwise: false)
            .stroke(style: StrokeStyle(lineWidth: 4, lineCap: .round))
                            .fill(Color.yellow)
                            .frame(width: 145, height: 145)

        
        ///BUTTON
        HStack(alignment: .top){
            Spacer()
        Button(action: addSum) {
            Image(systemName: "checkmark.circle")
                        .font(.title3)
                        .opacity(1)
          } .buttonStyle(MyButtonStyle())
        .frame(width: 30.0, height: 30.0)
        .clipShape(Circle())
        .disabled((yournewSum + summarize) <= summarize)
       }
        .padding(.bottom, 135.0)
        .padding(.horizontal, 8.0)
        
        VStack(alignment: .trailing, spacing: 0.0){
            Spacer()
            Text("$\((yournewSum + summarize), specifier: "%.f")")
                    .font(.title3)
                    .bold()
                    .padding(4)
                    .overlay(
                        RoundedRectangle(cornerRadius: 7)
                            .stroke(Color.white, lineWidth: 2)
                            .opacity(isFocusedSum ? 1.0:0.0)
                    )
                    .focusable(true) { newState in isFocusedSum = newState}
                    .animation(.easeInOut(duration: 0.3), value: isFocusedSum)
                    .digitalCrownRotation(
                        $yournewSum,
                        from: 0,
                        through: Double((Sum - summarize)),
                        by: 10,
                        sensitivity: .high
                    )
            
             
            Text("/ $\(item.neededSum, specifier: "%.f")")
            .font(.caption)
            .foregroundColor(Color.gray)
            .padding(3.5)
            
            Button(action: deleteGoal){
                Text("HO")
            }
      
        Spacer()
        }
    .frame(width: 200, height: 230)
    .padding(.top, 15)

    }
    }
    .padding([.top, .leading, .trailing], 5.0)
    
 }
 }

private func addSum(){
    let goal = goalItem == nil ? NewGoal(context: context): goalItem
    goal?.yourSum = yournewSum + summarize
    goal?.allNewSum = yournewSum + allNewSum
    do{
        try context.save()
        presentationMode.wrappedValue.dismiss()
    } catch let err{
        print(err.localizedDescription)
        }
}

private func deleteGoal(){ //// < -- Here it works
    if let goal = goalItem {
        context.delete(goal)
    do{
        try context.save()
        presentationMode.wrappedValue.dismiss()
    }catch let err{
        print(err.localizedDescription)
        }
  }
}
}

Solution

  • Change your delete method like this

    private func deleteGoal(goal: NewGoal){ 
            context.delete(goal)
        do{
            try context.save()
            presentationMode.wrappedValue.dismiss()
        }catch{
            print(error)
        }
    }
    

    And change your button to this

    Button(action: {
        deleteGoal(goal: item)
    }){
       Text("Delete") }