ios – Xcode EXC_BREAKPOINT (code=1, subcode=..) when delete Category and included expenses details


I am leaving a question for the first time. I am Korean, and I started developing it on my own a while ago. I am in a bind due to an ongoing issue recently. I am not even sure how many codes I need to attach to fill out a question for the first time. Please understand.
First of all, below is the Expense Model that I’m using. It happens when I delete DisclosureGroup as a swipe on the CategoryView screen. One peculiarity is that there is a difference between a real device and a virtual device using IOS 17 the same. In a virtual device, there is no problem of forced termination even if the process is repeated over and over again, but in a real device, forced termination occurs every time. I can’t get a sense of which part is the problem, so I’m asking for your help.

import SwiftUI
import SwiftData

@Model
class Expense : Identifiable {
    
    var title: String
    var amount: Double
    var date: Date

    var category: Category?
    
    
    init(title: String, amount: Double, date: Date, category: Category? = nil) {
        self.title = title
        self.amount = amount
        self.date = date
        self.category = category
    }

And below is the full text of the code where the problem occurs.

import SwiftUI
import SwiftData

struct CategoriesView: View {
    @Query(animation: .snappy) private var allCategories: [Category]
    @Query(sort: [SortDescriptor(\Expense.date, order: .reverse)], animation: .snappy) var allExpenses: [Expense]
    @Environment(\.modelContext) private var context
    @StateObject private var settingsViewModel = SettingsViewModel()
    
    
    @State  var addCategory: Bool = false
    @State  var categoryName: String = ""
    @State private var deleteRequest: Bool = false
    @State private var requestedCategory: Category?
    @State var addExpense: Bool = false
    @State  var setting: Bool = false
    @State var choosedDate : Date?
    @State private var addedCategory: Category?
    @State private var categoryNames: [String] = []
    @State private var currentTab: String = "Categories"
    @State private var categories: [Category] = []

    
    func sortedExpenses(for category: Category) -> [Expense]? {
        return allExpenses.filter { $0.category == category }.sorted(by: { $0.date < $1.date })
    }
    
    func categoryTotalAmount(category: Category) -> Double {
        let sortedExpenses = allExpenses.filter { $0.category == category }.sorted(by: { $0.date < $1.date })
        return sortedExpenses.reduce(0) { $0 + $1.amount }
    }
    
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(allCategories.sorted(by: {
                    ($0.expenses?.count ?? 0) > ($1.expenses?.count ?? 0)
                })) { category in
                    Section {
                        DisclosureGroup {
                            if let sortedExpenses = sortedExpenses(for: category) {
                                ForEach(sortedExpenses.indices, id: \.self) { index in
                                    let expense = sortedExpenses[index]
                                    HStack {
                                        Text(expense.date, formatter: dateFormatter)
                                            .textScale(.secondary)
                                        ExpenseCardView(expense: expense, displayTag: false)
                                            .environmentObject(settingsViewModel)
                                    }
                                    
                                    if index == sortedExpenses.indices.last {
                                        HStack {
                                            Text("total:")
                                                .multilineTextAlignment(.leading)
                                            Spacer()
                                            Text(formatCurrency(amount: categoryTotalAmount(category: category)))
                                                .foregroundColor(categoryTotalAmount(category: category) >= 0 ? .incomeAmount : .expenseAmount)
                                        }
                                    }
                                }
                                if !addExpense && sortedExpenses.indices.last == 0 {
                                    HStack {
                                        Spacer()
                                    }
                                }
                            }else {
                                ContentUnavailableView {
                                    Label("List is Empty", systemImage: "tray.fill")
                                }
                            }
                        } label: {
                            Text(category.categoryName)
                        }
                        .swipeActions(edge: .trailing, allowsFullSwipe: false) {
                            Button {
                                deleteRequest.toggle()
                                requestedCategory = category

                            } label: {
                                Image(systemName: "trash")
                            }
                            .tint(.delete)
                        }
                    }
                }
            }
            .navigationTitle("Category")
            .overlay(content: {
                if allCategories.isEmpty {
                    ContentUnavailableView {
                        Label("생성된 카테고리가 없습니다", systemImage: "tray.fill")
                    }
                }
            })
            
            .toolbar {
                           ToolbarItem(placement: .topBarTrailing) {
                               AppMenuView(addExpense: $addExpense, addCategory: $addCategory, setting: $setting)
                           }
                       }
            .onAppear {
                settingsViewModel.categoryNames = allCategories.map { $0.categoryName }
                categories = allCategories
            }
            .onChange(of: settingsViewModel.categoryListChanged) { newValue in
                settingsViewModel.categoryListChanged = newValue
                if currentTab == "Categories" {
                    currentTab = "Expenses"
                }
            }
            .onChange(of: allCategories) { updatedCategories in
                settingsViewModel.categoryNames = updatedCategories.map { $0.categoryName }
                categories = updatedCategories
                if currentTab == "Expenses" {
                    settingsViewModel.categoryListChanged.toggle()
                }
            }

            .onChange(of: allCategories) { updatedCategories in
                            settingsViewModel.categoryNames = updatedCategories.map { $0.categoryName }
                settingsViewModel.categoryListChanged.toggle()
            }
            .sheet(isPresented: $addCategory) {
                categoryName = ""
                
            } content: {
                NavigationStack {
                    List {
                        Section("Category Name") {
                            TextField("Please enter a category name.", text: $categoryName)
                        }
                    }
                    .navigationTitle("New Category Name")
                    .navigationBarTitleDisplayMode(.inline)
                    .toolbar {
                        ToolbarItem(placement: .topBarLeading) {
                            Button("cancel") {
                                addCategory = false
                            }
                            .tint(.cancel)
                        }
                        
                        ToolbarItem(placement: .topBarTrailing) {
                            Button("add") {
                                let category = Category(id: UUID(), categoryName: categoryName)
                                context.insert(category)
                                
                                addedCategory = category
                                
                                categoryName = ""
                                addCategory = false
                            }
                            .disabled(categoryName.isEmpty)
                        }
                    }
                }
                .presentationDetents([.height(180)])
                .interactiveDismissDisabled()
            }
            
        }
        .alert("When you delete a category, the details specified in the category are also deleted. Are you sure you want to delete it?", isPresented: $deleteRequest){
            Button(role: .destructive) {
                if let requestedCategory {
                    let expensesToDelete = allExpenses.filter { $0.category == requestedCategory }
                                expensesToDelete.forEach { context.delete($0) }
                    
                    
                    context.delete(requestedCategory)
                    self.requestedCategory = nil
                    
                    settingsViewModel.categoryListChanged.toggle()

                }
                
            } label: {
                Text("delete")
                
            }
            
            Button(role: .cancel) {
                requestedCategory = nil
            } label: {
                Text("cancel")
                
            }
            
            
        }
        .sheet(isPresented: $addExpense) {
            AddExpenseView()
                .interactiveDismissDisabled()
        }
        .sheet(isPresented: $setting) {
            SettingsView()
                .interactiveDismissDisabled()
        }
        
    }

At first, I thought that there was a problem because of the overlapping part of the on-change, so I tried to modify the on-change, delete unnecessary comments, and so on, but I still haven’t solved it.

I’m attaching it together because I might need it
https://github.com/gara-age/Malendar

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img