【问题标题】:upload many files and save in CoreData上传许多文件并保存在 CoreData
【发布时间】:2015-08-24 12:06:28
【问题描述】:

使用 API 我得到 500 张图片,异步上传它们。然后我想把这些图片全部保存在CoreData中,但是由于内存不足,应用程序崩溃了。

上传完成后我调用方法createFromBlock

+(id)createFromBlock:(MRBlock *)block{
    ManagedBlock *item = [ManagedBlock MR_createInContext:DefaultContext];
    item.id = @(block.id);
    item.name = block.name;
    item.slidesInBlock =  @(block.slidesInBlock);

    item.sizeBlock = block.sizeBlock;
    item.desc = block.desc;
    item.imagePath = block.imagePath;
    item.image = [MRUtils transformedValue:block.image];
    item.price = block.price;
    int i = 0;
    ManagedItem *new = nil;
    for (MRItem *lol in block.items){
        NSLog(@"%i", i);
                        new = [ManagedItem createFromItem:lol];
                new.block = item;
                [item addItemsObject:new];
        new = nil;
        i++;
    }

    [DefaultContext MR_saveWithOptions:MRSaveSynchronously completion:nil];

    return item;
}

在 foreach block.items 应用程序崩溃。大约在 150-160 个位置之后。

如果我评论 new = [ManagedItem createFromItem:lol]; - 应用程序不会崩溃

+(id)createFromItem:(MRItem *)object{
    ManagedItem *item = [ManagedItem MR_createInContext:DefaultContext];
    item.id = @(object.id);
    item.title = object.title;
    item.detail = object.detail;
    item.imagePath = object.imagePath;
    item.image = [MRUtils transformedValue:object.image];
    return item;
}

【问题讨论】:

  • 您是否分批这样做?还是一次性完成 - 一次循环 500 个?
  • Grzegorz Krukowski,一次完成 - 500 个循环

标签: ios objective-c core-data nsarray


【解决方案1】:

首先,您不应该加载所有数据然后保存。您应该小批量加载,并保存每个批次。

但是,对于您的具体示例,我相信您可以在保存后将每个对象变成故障。

我从来没有使用过魔法记录,也不知道它是否允许你在不调用它的方法的情况下做上下文相关的事情。我看过一次,但它对我来说隐藏了太多细节......除非你在做最基本的事情,否则核心数据可能非常复杂,我想知道我的核心数据代码发生的一切。

+(id)createFromBlock:(MRBlock *)block{
  @autoreleasepool {
    ManagedBlock *item = [ManagedBlock MR_createInContext:DefaultContext];
    item.id = @(block.id);
    item.name = block.name;
    item.slidesInBlock =  @(block.slidesInBlock);

    item.sizeBlock = block.sizeBlock;
    item.desc = block.desc;
    item.imagePath = block.imagePath;
    item.image = [MRUtils transformedValue:block.image];
    item.price = block.price;

    NSUInteger const batchSize = 10;
    NSUInteger count = block.items.count;
    NSUInteger index = 0;
    while (index < count) {
      @autoreleasepool {
        NSMutableArray *newObjects = [NSMutableArray array];
        for (NSUInteger batchIndex = 0;
             index < count && batchIndex < batchSize;
             ++index, ++batchIndex) {
          MRItem *lol = [block.items objectAtIndex:index];
          ManagedItem *new = [ManagedItem createFromItem:lol];
          new.block = item;
          [item addItemsObject:new];
          [newObjects addObject:new];
        }
        [DefaultContext MR_saveWithOptions:MRSaveSynchronously completion:nil];
        for (NSManagedObject *object in newObjects) {
          // Don't know if MagicalRecord will like this or not...
          [DefaultContext refreshObject:object mergeChanges:NO];
        }
      }
    }

    return item;
}

基本上,该代码一次处理 10 个对象。当该批次完成时,上下文被保存,然后将这 10 个对象变成故障,释放它们持有的内存。自动释放池确保在包含范围内创建的任何对象都在范围退出时被释放。如果没有其他对象持有这些对象的保留,那么它们将被释放。

在处理 Core Data 中的大数字或大对象时,这是一个关键概念。此外,了解@autoreleasepool 非常重要,尽管从未使用过 MRR 的人不会欣赏它的好处。

顺便说一句,我只是在编辑器中输入了它,所以不要指望它可以通过简单的复制/粘贴来编译和运行。

【讨论】:

    猜你喜欢
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    • 2023-03-18
    相关资源
    最近更新 更多