Deleting master data after X days
So I have a bunch of objects in Core Data and want them to be deleted automatically after X days (that would be NSDate based). I have done several searches and it seems that you can only delete one main data object at a time, not a group of them, let alone those based on a specific date. I think it is possible for the loop to loop through each object, but it looks like it will be a very heavy processor. Any ideas on where I should be looking for this? Thank.
source to share
A loop deleting objects one by one is the correct approach.
Deleting objects in Core Data is extremely difficult. If this is a problem, then Core Data is not suitable for your project and you must be using something else. I recommend FCModel as a very lightweight alternative.
If you are going to use Core Data, it is recommended that you do large operations in the background of the NSOperationQueue, so the main application does not block when objects are deleted. You have to be very careful with master data across multiple threads, the approach is to have a separate managed object context for each thread, just like using the same persistent store coordinator. Never stream a managed object, but you can share an object identifier to get a second copy of the same database record in a different managed object context.
Basically your background thread creates a new context, deletes all objects in the loop, then (on the main thread, preferably see the documentation) preserves the background thread's context. This will merge your changes unless there is a conflict (both contexts are modifying the same object) - in this scenario you have multiple options, I would just stop the whole delete operation and start over.
Apple has good documentation for all issues and sample code available here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdConcurrency.html
It's a little tricky, you have some serious homework to do, but the actual code is very simple if you have your head around how things work. Or just use FCModel which is for fast batch operations.
source to share
It's not as heavy as you think as a processor :) (of course it depends on the amount of data)
Don't use a loop
- (void)deleteAllObjects
{
NSArray *allEntities = self.managedObjectModel.entities;
for (NSEntityDescription *entityDescription in allEntities)
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entityDescription];
fetchRequest.includesPropertyValues = NO;
fetchRequest.includesSubentities = NO;
NSError *error;
NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *managedObject in items) {
[self.managedObjectContext deleteObject:managedObject];
}
if (![self.managedObjectContext save:&error]) {
NSLog(@"Error occurred");
}
}
}
source to share
As others have noted, iterating over objects is the only way to actually delete objects in Core Data. This is one of those cases where the Core Data approach comes close because it just isn't optimized for that use.
But there are ways to handle this to avoid unwanted delays in your application so that the user doesn't have to wait for your code to intercept a ton of delete requests.
If you have a lot of objects to delete and you don't want to wait for the process to complete, you can fake the initial deletion first and then do the actual deletion when convenient. Something like:
- Add a custom boolean attribute to an entity type named as
toBeDeleted
with a default valueNO
. - Once you have a bunch of objects to delete, set
toBeDeleted
inYES
for all of them in one step usingNSBatchUpdateRequest
(new in iOS 8). This class is mostly undocumented, so take a look at the header file or BNR blog post about it . You supply the property name and the new attribute value, and Core Data will be a massive, fast update. - Make sure your fetch requests check that
toBeDeleted
NO
. Objects marked for deletion will now be excluded from checkout, even if they still exist. - At some point - later, but soon - run some code in the background that retrieves and removes objects with
toBeDeleted
set toYES
.
source to share