编辑:刚刚观看了 2015 年 WWDC “ Core Data 中的新功能”(它一直是我观看的第一个视频,但今年我一直很忙),他们宣布了一个新的 API:NSBatchDeleteRequest
这应该比以前的任何解决方案都更有效率。
高效有多种含义,通常意味着某种权衡。在这里,我假设您只想在删除时包含内存。
Core Data 有很多性能选项,超出了任何单个 SO 问题的范围。
如何管理内存取决于 managedObjectContext 和 fetchRequest 的设置。查看文档以查看所有选项。但是,特别是,您应该牢记这些事情。
另外,请记住性能方面。这种类型的操作应该在单独的线程上执行。
另外,请注意,对象图的其余部分也将发挥作用(因为 CoreData 如何处理相关对象的删除。
关于内存消耗,MOC 有两个属性需要特别注意。虽然这里有很多,但绝不是全面的。如果您想实际查看发生了什么,请在每次保存操作之前和之后 NSLog 您的 MOC。特别是记录已注册对象和已删除对象。
MOC 有一个已注册对象的列表。默认情况下,它不保留已注册的对象。但是,如果 retainsRegisteredObjects 为 YES,它将保留所有已注册的对象。
特别是对于删除,setPropagatesDeletesAtEndOfEvent 告诉 MOC 如何处理相关对象。如果您希望它们与保存一起处理,则需要将该值设置为 NO。否则,它将等到当前事件完成
如果您有非常大的对象集,请考虑使用 fetchLimit。虽然故障不会占用大量内存,但它们仍会占用一些内存,而且一次有数千个并非微不足道。这意味着更多的获取,但你会限制内存量
还要考虑,任何时候你有很大的内部循环,你应该使用你自己的自动释放池。
如果此 MOC 有父级,则保存只会将这些更改移动到父级。在这种情况下,如果你有一个父 MOC,你只是让那个 MOC 成长。
对于限制内存,请考虑这一点(不一定最适合您的情况 - 有很多Core Data 选项 - 只有您知道什么最适合您的情况,基于您在其他地方使用的所有选项。
我在 NSManagedObjectContext 上写了一个类别,当我想确保保存到后备存储时用于保存,与此非常相似。如果您不使用 MOC 层次结构,则不需要它,但是......确实没有理由不使用层次结构(除非您绑定到旧 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;
}
我稍微修改了你的代码......
+ (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];
}
}