ios - 在核心数据中删除大量(10.000+)对象的最有效方法是什么?

标签 ios core-data

我尝试删除多组 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。

  1. MOC 有一个已注册对象的列表。默认情况下,它不保留已注册的对象。但是,如果 retainsRegisteredObjects 为 YES,它将保留所有已注册的对象。

  2. 特别是对于删除,setPropagatesDeletesAtEndOfEvent 告诉 MOC 如何处理相关对象。如果你想让它们在保存时得到处理,你需要将该值设置为 NO。否则,它会等到当前事件完成

  3. 如果您有非常大的对象集,请考虑使用 fetchLimit。虽然故障不会占用大量内存,但它们仍会占用一些内存,而且一次数千个并非微不足道。这意味着更多的获取,但是你会限制内存量

  4. 另外请考虑,只要您有大型内部循环,就应该使用自己的自动释放池。

  5. 如果此 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/

相关文章:

ios - 2018 在 Objective-C 中向 NSURL 添加查询字符串的方法

iphone - 每个细节 View Controller 一个计时器

iphone - 我的类应该转换为核心数据管理对象,还是核心数据管理对象

objective-c - 具有内存存储的核心数据

ios - 检测核心数据的删除

iphone - 何时*不*使用 Core Data 类型 Transformable?

ios - 无法在 tableView iOS 中获取已解析的数组

iOS 动画虚线矩形边框

ios - 通过 JSON 层次结构和 objectForKey 使用 AFNetworking 加载 ImageView

iphone - NSPredicate同时使用IN和LIKE