EDIT : just watched 2015 WWDC βWhat's New in Core Dataβ (it's always the first video I watch, but I'm very busy this year) and they announced a new API: NSBatchDeleteRequest
, which should be much more efficient than any previous decision.
Efficiency has several meanings and most often means some kind of compromise. Here, I am assuming that you just want to contain memory on deletion.
Master data has many performance parameters that go beyond any single SO issue.
How memory is managed depends on the settings for the managed objects and the fetchRequest context. View documents to see all options. In particular, you should keep this in mind.
Also, keep in mind the performance aspect. This type of operation must be performed in a separate thread.
Also, note that the rest of your object graph will also come into play (due to the way CoreData handles the removal of related objects.
Regarding memory consumption, in MOC, in particular, pay attention to two properties. Although there are many, it is in no way close to comprehensive. If you want to see what happens, NSLog is your MOC before and after each save operation. In particular, log registeredObjects and deletedObjects.
The MOC has a list of registered objects. By default, it does not save registered objects. However, if preservesRegisteredObjects is set to YES, it will retain all registered objects.
For deletion, in particular, setPropagatesDeletesAtEndOfEvent tells the MOC how to handle related objects. If you want them to be processed with preservation, you need to set this value to NO. Otherwise, it will wait for the current event to complete.
If you have really large objects, consider using fetchLimit. While errors do not take up a lot of memory, they still accept some, and many thousands are not insignificant at the same time. This means more sampling, but you will limit the amount of memory
Also think that anytime you have large internal loops, you should use your own autostart pool.
If this MOC has a parent, saving only moves these changes to the parent. In this case, if you have a parent MOC, you just make it grow.
To limit memory, consider this (not necessarily the best for your case - many Core Data options - only you know what is best for your situation, based on all the parameters that you use elsewhere.
I wrote a category in NSManagedObjectContext that I use to save when I want to make sure the save goes to a repository very similar to this. If you do not use the MOC hierarchy, you do not need it, but ... there is no reason NOT to use the hierarchy (if you are not tied to the old iOS).
- (BOOL)cascadeSave:(NSError**)error { __block BOOL saveResult = YES; if ([self hasChanges]) { saveResult = [self save:error]; } if (saveResult && self.parentContext) { [self.parentContext performBlockAndWait:^{ saveResult = [self.parentContext cascadeSave:error]; }]; } return saveResult; }
I changed your code a bit ...
+ (void)deleteRelatedEntitiesInManagedObjectContext:(NSManagedObjectContext *)context { NSFetchRequest *fetch = [[NSFetchRequest alloc] init]; [context setUndoManager:nil]; [fetch setEntity:[NSEntityDescription entityForName:NSStringFromClass(self) inManagedObjectContext:context]]; [fetch setIncludesPropertyValues:NO]; [fetch setFetchLimit:500]; NSError *error = nil; NSArray *entities = [context executeFetchRequest:fetch error:&error]; while ([entities count] > 0) { @autoreleasepool { for (NSManagedObject *item in entities) { [context deleteObject:item]; } if (![context cascadeSave:&error]) {