swift-data

SwiftData EXC_BREAKPOINT when setting relationship


I'm working with SwiftData for the first time and having trouble with crashes when I try to set the value of a relationship.

I have a Profession object which represents a job in the game. Each Profession can have expenses (Expense, like a mortgage payment).

I'm trying to populate the initial data when the app first launches. When I'm creating the first Profession, I create one Expense which seems to work but when I create a second Expense the app crashes with Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1c3c6203c) when trying to set the Expense.profession relationship. Xcode expands the profession property to show the get/set and it's crashing in the set function.

Am I missing something obvious? Or is SwiftData expecting me to do something very different than CoreData would in this case?

@Model
class Profession {
    var id: UUID
    var name: String
    
    @Relationship(deleteRule: .cascade, inverse: \Expense.profession) var expenses: [Expense] = []
        
    init(name: String) {
        self.id = UUID()
        self.name = name
    }
    
    convenience init(professiondefault: ProfessionDefault) {
        self.init(name: professiondefault.name)
        
        let taxes = Expense(name: "Taxes", cashflow: professiondefault.taxes, isPermanent: true, profession: self)
        
        // crashes on the next line
        let otherExpenses = Expense(name: "Other Expenses", cashflow: professiondefault.otherExpenses, isPermanent: true, profession: self)
        
    }
    
}


@Model
class Expense {
    let id: UUID
    var cashflow: Int
    let isPermanent: Bool
    var name: String
    
    var profession: Profession? 
    
    init(name: String, cashflow: Int, isPermanent: Bool, profession: Profession? = nil) {
        self.id = UUID()
        self.cashflow = cashflow
        self.isPermanent = isPermanent
        self.name = name
        self.profession = profession
    }
    
}

Solution

  • I believe I have found a pattern for how to make this work. When creating two related objects at the same time then you need insert the one you want to assign to into your model context first before connecting the two

    So this works

    let profession = Profession(name: "New profession")
    modelContext.insert(profession) // <-- Insert first
    let expense1 = Expense(name: "Expense 1", cashflow: 10, isPermanent: false)
    let expense2 = Expense(name: "Expense 2", cashflow: 10, isPermanent: false)
    profession.expenses.append(contentsOf: [expense1, expense2])
    
    // this is also ok 
    //  profession.expenses.append(expense1)
    //  profession.expenses.append(expense2)
    
    

    And if we want to assign a profession to an expense this works:

    let profession2 = Profession(name: "New profession")
    let expense3 = Expense(name: "Expense 3", cashflow: 10, isPermanent: false)
    let expense4 = Expense(name: "Expense 4", cashflow: 10, isPermanent: false)
    
    modelContext.insert(expense3) // <-- Insert first
    expense3.profession = profession2
    modelContext.insert(expense4) // <-- Insert first
    expense4.profession = profession2