Post

Replies

Boosts

Views

Activity

Crash during batch deletion merge when positive fractional decimals are stored and used in a derived attribute
I am experiencing a crash when performing a batch delete and merging changes on a Core Data store that uses NSPersistentCloudKitContainer. The crash appears to be triggered when positive fractional Decimal values are stored in a TransactionSplit entity (those values are aggregated via a derived attribute in the AccountTransaction entity). If I store whole numbers or negative fractional decimals, deletion seems to work correctly. I suspect that the issue is related to the internal representation of positive fractional decimals in conjunction with a derived attribute. Data Model Setup: Account (1:N relationship → AccountTransaction) AccountTransaction (1:N relationship → TransactionSplit), which contains a derived attribute (e.g., “splits.amount.@sum”) that computes the sum over the “amount” attribute on its related TransactionSplit objects. TransactionSplit, which contains a stored Decimal attribute named “amount” (of type Decimal/NSDecimalNumber). Steps to Reproduce: Insert sample data where each TransactionSplit’s “amount” is set to a positive fractional value (e.g., 1000.01), by using code similar to: func createSampleData() { // Execute all creation on the context’s queue. let checkingAccount = Account(context: context) checkingAccount.id = UUID() checkingAccount.name = "Main Checking" let randomTransactionCount = 1000 for _ in 0..<randomTransactionCount { let transaction = AccountTransaction(context: context) transaction.id = UUID() transaction.account = checkingAccount let randomValue = Double.random(in: 5...5000) let decimalValue = NSDecimalNumber(value: randomValue) let split1 = TransactionSplit(context: context) split1.id = UUID() split1.amount = decimalValue split1.transaction = transaction let split2 = TransactionSplit(context: context) split2.id = UUID() split2.amount = decimalValue split2.transaction = transaction } save() } The AccountTransaction’s derived attribute automatically aggregates the sum of its related TransactionSplit amounts. Perform a batch deletion using NSBatchDeleteRequest (with resultType set to .resultTypeObjectIDs) on your entities and merge the changes back into your main context: private func delete(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) { let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) batchDeleteRequest.resultType = .resultTypeObjectIDs // ⚠️ When performing a batch delete we need to make sure we read the result back // then merge all the changes from that result back into our live view context // so that the two stay in sync. if let delete = try? context.execute(batchDeleteRequest) as? NSBatchDeleteResult { let changes = [NSDeletedObjectsKey: delete.result as? [NSManagedObjectID] ?? []] NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context]) } } Save the context after deletion.
4
0
501
Mar ’25