我尝试删除多组 10.000+ NSManagedObjects 的方式过于占用内存(大约 20MB 事件字节),我的应用程序被抛弃了。下面是删除方法的实现:
+ (void)deleteRelatedEntitiesInManagedObjectContext:(NSManagedObjectContext *)context
{
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
[context setUndoManager:nil];
[fetch setEntity:[NSEntityDescription entityForName:NSStringFromClass(self) inManagedObjectContext:context]];
[fetch setIncludesPropertyValues:NO];
NSError *error = nil;
NSArray *entities = [context executeFetchRequest:fetch error:&error];
NSInteger deletedCount = 0;
for (NSManagedObject *item in entities) {
[context deleteObject:item];
deletedCount++;
if (deletedCount == 500) {
[context save:&error];
deletedCount = 0;
}
}
if (deletedCount != 0) {
[context save:&error];
}
}
我试过:-setFetchBatchSize,但使用的内存更多。
执行此操作的内存效率更高的方法是什么?
最佳答案
编辑:刚看了 2015 WWDC“Core Data 的新功能”(这一直是我看的第一个视频,但今年我一直很忙)和他们宣布了一个新的 API:NSBatchDeleteRequest
,它应该比以前的任何解决方案都更有效率。
高效有多种含义,通常意味着某种权衡。在这里,我假设您只想在删除时包含内存。
Core Data 有很多性能选项,超出了任何单个 SO 问题的范围。
如何管理内存取决于您的 managedObjectContext 和 fetchRequest 的设置。查看文档以查看所有选项。不过,您尤其应该记住这些事情。
另外,请记住性能方面。此类操作应在单独的线程上执行。
另外,请注意您的对象图的其余部分也会发挥作用(因为 CoreData 如何处理相关对象的删除。
关于内存消耗,MOC上有两个属性需要特别注意。虽然这里有很多,但绝不是全面的。如果您想实际查看发生了什么,请在每次保存操作之前和之后 NSLog 您的 MOC。特别是记录 registeredObjects 和 deletedObjects。
MOC 有一个已注册对象的列表。默认情况下,它不保留已注册的对象。但是,如果 retainsRegisteredObjects 为 YES,它将保留所有已注册的对象。
特别是对于删除,setPropagatesDeletesAtEndOfEvent 告诉 MOC 如何处理相关对象。如果你想让它们在保存时得到处理,你需要将该值设置为 NO。否则,它会等到当前事件完成
如果您有非常大的对象集,请考虑使用 fetchLimit。虽然故障不会占用大量内存,但它们仍会占用一些内存,而且一次数千个并非微不足道。这意味着更多的获取,但是你会限制内存量
另外请考虑,只要您有大型内部循环,就应该使用自己的自动释放池。
如果此 MOC 有父级,则保存只会将这些更改移动到父级。在这种情况下,如果您有一个父 MOC,您只是在让它成长。
为了限制内存,请考虑这个(不一定最适合您的情况 -- 有 很多 Core Data 选项 -- 只有您知道什么最适合您的情况,基于您的所有选项正在别处使用。
我在 NSManagedObjectContext 上写了一个类别,当我想确保保存到后备存储时,我用它来保存,与此非常相似。如果您不使用 MOC 层次结构,则不需要它,但是……真的没有理由不使用层次结构(除非您绑定(bind)到旧 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];
}
}
关于ios - 在核心数据中删除大量(10.000+)对象的最有效方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10581569/