使用Core Data进行对象数组的内存高效插入方法

7
我正在为iPhone应用程序编写一段代码,从服务器获取大量数据并在客户端构建对象。最终会创建大约40,000个对象。它们不会显示给用户,我只需创建NSManagedObject的实例并将其存储到持久性存储中。
我认为唯一的方法是创建一个单一的对象,然后保存上下文,这样想是否正确?最好一次性创建所有对象,然后在创建并存储到某个集合或数组后将它们保存到上下文中吗?如果是这样,请给出一些示例代码或指向已经完成此操作的代码的方向。
这些对象本身都是相对简单的模型,具有字符串或整数属性,并且不包含任何复杂的关系。
3个回答

5
无论如何,不要在每次插入对象后保存,否则应用程序性能会极差。
以下是我在首次启动时使用的代码,用于填充Core Data存储库。
#define MAX_UNSAVED_AIRPORTS_BEFORE_SAVE 1000
int numAirports = 0;
int numUnsavedAirports = MAX_UNSAVED_AIRPORTS_BEFORE_SAVE; // *** bug. see below
for (NSDictionary *anAirport in initialAirports) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    Airport *newAirport = [NSEntityDescription insertNewObjectForEntityForName:@"Airport" inManagedObjectContext:managedObjectContext];

    newAirport.city         = [anAirport objectForKey:@"city"];
    newAirport.code         = [anAirport objectForKey:@"code"];
    newAirport.name         = [anAirport objectForKey:@"name"];
    newAirport.country_name = [anAirport objectForKey:@"country_name"];
    newAirport.latitude     = [NSNumber numberWithDouble:[[anAirport objectForKey:@"latitude"] doubleValue]];
    newAirport.longitude    = [NSNumber numberWithDouble:[[anAirport objectForKey:@"longitude"] doubleValue]];
    newAirport.altitude     = [NSNumber numberWithDouble:[[anAirport objectForKey:@"altitude"] doubleValue]];

    numAirports++;
    numUnsavedAirports++;
    if (numUnsavedAirports >= MAX_UNSAVED_AIRPORTS_BEFORE_SAVE) {
        if (![managedObjectContext save:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
        numUnsavedAirports = 0;
    }
    [pool release];
}

还要在循环后保存最后一次。

请注意,如果满足以下三个条件,则存在导致崩溃的错误:

  1. 存储库为空
  2. 您拥有一个具有分区的UITableView
  3. 第一次保存保存了多个对象。

上面代码中的解决方法是将numUnsavedAirports初始化为MAX_UNSAVED_AIRPORTS_BEFORE_SAVE,以确保在第一个插入之后发生第一次保存。

希望这可以帮助您。


3

每个对象保存一次会导致性能非常差。你应该在平衡考虑每隔 100 次保存 (测试将确定最佳点),并在用户退出时跟踪处理的进度。

退出时,您可以获得时间来存储状态,以便轻松存储数据处理中的位置 (每次保存 5 个 100 个块),并从上次离开的地方继续。

每个对象单独保存将会大量使用磁盘空间,使应用程序变得缓慢。


除了这个正确的建议,你还应该考虑在保存后重置ManagedObjectContext以减少内存占用。但要注意,重置上下文会使您失去该上下文中的任何中间结果。例如,批量获取结果也会消失。 - Bjinse
相关的苹果文档在这里:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html - Bjinse

1

最好创建一个单一的对象并保存上下文。

你有40k个对象。假设创建一个单一的NSManagedObject需要x个时间单位。40kx个时间单位可能是可测量的。当对象创建正在进行时,用户可能因某种原因退出应用程序;用户是不可预测的。下次您的应用程序启动时,您将再次经历整个过程。创建第39,999个对象只为了让用户退出应用程序并失去所有工作是不可取的。

如果您的应用程序创建每个对象并保存,您可以加快此过程。应用程序启动并检查上次运行是否能够完成任务。如果任务未完成,则可以尝试从上次离开的地方继续。

单个对象创建和保存方法可能需要更长的时间才能完成,但完成任务的可能性更大。

在内存消耗方面,这也最小化了应用程序的内存状态。上下文没有在内存中跟踪40k个对象。


2
将每个对象单独保存会导致性能非常差。 - Marcus S. Zarra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接