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.
Thanks. Yeah, this is pretty much the same as the known issue I mentioned (r.96632321), which happens when derived attribute @sum
+ Decimal
is used.
I’d still suggest that you file your own feedback report to hopefully draw more attentions – If you do so, please share your report ID here for folks to track.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.