在 Core Data 中删除大量(10.000+)对象的最有效方法是什么? [英] What is the most efficient way to delete a large number (10.000+) objects in Core Data?

查看:24
本文介绍了在 Core Data 中删除大量(10.000+)对象的最有效方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试删除多组 10.000+ NSManagedObjects 的方式太占用内存(大约 20MB 活动字节),我的应用程序被抛弃了.下面是删除方法的实现:

The way I'm trying to delete multiple sets of 10.000+ NSManagedObjects is just too memory intensive (around 20MB live bytes), and my app is being jettisoned. Here is the implementation of the delete method:

+ (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,但使用的内存更多.

I've tried: -setFetchBatchSize, but there's even more memory used.

什么是更节省内存的方法来做到这一点?

What would be a more memory-efficient way to do this?

推荐答案

EDIT:刚看了 2015 年 WWDCCore Data 的新变化"(它总是第一个视频我在看,但今年我一直很忙)他们宣布了一个新的 API:NSBatchDeleteRequest,它应该比以前的任何解决方案都更有效率.

EDIT: Just watched 2015 WWDC "What's New in Core Data" (it's always the first video I watch, but I've been very busy this year) and they announced a new API: NSBatchDeleteRequest that should be much more efficient than any previous solution.

高效有多种含义,通常意味着某种权衡.在这里,我假设您只想在删除时包含内存.

Efficient has multiple meanings, and most often means some sort of trade-off. Here, I assume you just want to contain memory while deleting.

Core Data 有很多的性能选项,超出了任何单一 SO 问题的范围.

Core Data has lots of performance options, beyond the scope of any single SO question.

内存的管理方式取决于 managedObjectContext 和 fetchRequest 的设置.查看文档以查看所有选项.不过,您尤其应该牢记这些事情.

How memory is managed depends on the settings for your managedObjectContext and fetchRequest. Look at the docs to see all the options. In particular, though, you should keep these things in mind.

另外,请记住性能方面.此类操作应在单独的线程上执行.

Also, keep in mind the performance aspect. This type of operation should be performed on a separate thread.

另外,请注意对象图的其余部分也将发挥作用(因为 CoreData 如何处理相关对象的删除.

Also, note that the rest of your object graph will also come into play (because of how CoreData handles deletion of related objects.

关于内存消耗,MOC 有两个属性需要特别注意.虽然这里有很多,但它绝不是全面的.如果您想实际查看发生了什么,请在每次保存操作之前和之后 NSLog 您的 MOC.特别是,记录registeredObjects 和deletedObjects.

Regarding memory consumption, there are two properties on MOC in particular to pay attention to. While there is a lot here, it is by no means close to comprehensive. If you want to actually see what is happening, NSLog your MOC just before and after each save operation. In particular, log registeredObjects and deletedObjects.

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

  1. The MOC has a list of registered objects. By default, it does not retain registered objects. However, if retainsRegisteredObjects is YES, it will retain all registered objects.

特别是对于删除,setPropagatesDeletesAtEndOfEvent 告诉 MOC 如何处理相关对象.如果您希望通过保存处理它们,则需要将该值设置为 NO.否则,它会一直等到当前事件完成

For deletes in particular, setPropagatesDeletesAtEndOfEvent tells the MOC how to handle related objects. If you want them handled with the save, you need to set that value to NO. Otherwise, it will wait until the current event is done

如果您有非常大的对象集,请考虑使用 fetchLimit.虽然故障不会占用大量内存,但它们仍然会占用一些内存,并且一次上千次并不是无关紧要的.这意味着更多的获取,但你会限制内存量

If you have really large object sets, consider using fetchLimit. While faults do not take a lot of memory, they still take some, and many thousands at a time are not insignificant. It means more fetching, but you will limit the amount of memory

还要考虑,每当您有大型内部循环时,您都应该使用自己的自动释放池.

Also consider, any time you have large internal loops, you should be using your own autorelease pool.

如果此 MOC 有父级,则保存只会将这些更改移动到父级.在这种情况下,如果你有一个父 MOC,你只是在让它成长.

If this MOC has a parent, saving only moves those changes to the parent. In this case, if you have a parent MOC, you are just making that one grow.

对于限制内存,请考虑这一点(不一定最适合您的情况——有 很多 Core Data 选项——只有您知道什么最适合您的情况,基于您的所有选项在别处使用.

For restricting memory, consider this (not necessarily best for your case -- there are lots of Core Data options -- only you know what is best for your situation, based on all the options you are using elsewhere.

我在 NSManagedObjectContext 上写了一个类别,当我想确保保存到后备存储时,我用它来保存,与此非常相似.如果您不使用 MOC 层次结构,则不需要它,但是...确实没有理由不使用层次结构(除非您绑定到旧 iOS).

I wrote a category on NSManagedObjectContext that I use for saving when I want to make sure the save goes to the backing store, very similar to this. If you do not use a MOC hierarchy, you don't need it, but... there is really no reason NOT to use a hierarchy (unless you are bound to 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 modified your code a little 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]) {
                // Handle error appropriately
            }
        }
        entities = [context executeFetchRequest:fetch error:&error];
    }
}

这篇关于在 Core Data 中删除大量(10.000+)对象的最有效方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆