EDITAR: Acabo de ver 2015 WWDC "¿Qué hay de nuevo en la base de datos" (que siempre es el primer video que observo, pero he estado muy ocupado este año) y se anunció una nueva API: NSBatchDeleteRequest
que debe ser mucho más eficiente que cualquier solución anterior.
Eficiente tiene múltiples significados, y la mayoría de las veces significa algún tipo de compensación. Aquí, supongo que solo quieres contener memoria mientras borras.
Datos principales tiene lotes de opciones de rendimiento, más allá del alcance de cualquier pregunta SO.
El manejo de la memoria depende de la configuración de managedObjectContext y fetchRequest. Mire los documentos para ver todas las opciones. En particular, sin embargo, debes tener esto en cuenta.
Además, tenga en cuenta el aspecto del rendimiento. Este tipo de operación debe realizarse en un hilo separado.
Además, tenga en cuenta que el resto de su gráfico de objetos también se pondrá en juego (por la forma en CoreData maneja eliminación de objetos relacionados.
En cuanto al consumo de memoria, hay dos propiedades en MOC en particular, a prestar atención a .Si bien hay mucho aquí, de ninguna manera es similar a exhaustivo. Si quiere ver realmente lo que está sucediendo, NSLog su MOC justo antes y después de cada operación de guardado. En particular, registre Objects registrados y deletedObjects.
El MOC tiene una lista de objetos registrados. Por defecto, no retiene los objetos registrados. Sin embargo, si retainsRegisteredObjects es SÍ, retendrá todos los objetos registrados.
Para las eliminaciones en particular, setPropagatesDeletesAtEndOfEvent le dice al MOC cómo manejar los objetos relacionados. Si desea que se manejen con el guardado, debe establecer ese valor en NO. De lo contrario, esperará hasta que se complete el evento actual
Si tiene conjuntos de objetos realmente grandes, considere usar fetchLimit. Si bien las fallas no requieren mucha memoria, todavía toman algunas y muchas miles a la vez no son insignificantes. Significa más búsqueda, pero limitará la cantidad de memoria
También considere, cada vez que tenga bucles internos grandes, debería utilizar su propio grupo de liberación automática.
Si este MOC tiene un padre, guardar solo mueve los cambios al padre. En este caso, si tiene un MOC padre, solo lo está haciendo crecer.
Para restringir la memoria, considere esto (no necesariamente mejor para su caso - hay un montón de opciones de Datos Básicos - sólo usted sabe lo que es mejor para su situación, sobre la base de todas las opciones que te en otro lugar.
Escribí una categoría en NSManagedObjectContext que uso para guardar cuando quiero asegurarme de que el guardado va al almacén de respaldo, muy similar a esto. Si no usa una jerarquía MOC, no lo hace lo necesito, pero ... realmente no hay razón para NO usar una jerarquía (a menos que esté vinculado al iOS anterior).
- (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;
}
he modificado su código un poco ...
+ (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]) {
// Handle error appropriately
}
}
entities = [context executeFetchRequest:fetch error:&error];
}
}
Optimizaciones que funcionaron: 1. eliminar la línea -setIncludesPropertyValues; 2. cambiar el límite de búsqueda de 500 a 2500 (¡en serio!); 3.use @autoreleasepool –