核心数据导入失败

时间:2011-02-08 17:54:17

标签: iphone objective-c core-data memory-leaks

我正在尝试将大型数据集(~6,000)导入到我的核心数据应用程序中。我已经阅读了Apple文档“有效导入数据”,我认为我正确设置了它。奇怪的是应用程序没有在模拟器中崩溃,虽然如果我使用Leaks仪器运行它,但它没有保存所有数据。有时它只会节省3-4百倍,它将节省3-4千,很少整个数据集。我认为它可能与内存泄漏有关,我对使用NSAutoReleasePool很新,任何帮助都会非常感激。

    NSURL *url = [NSURL URLWithString:@""];

    NSString *responseString = [NSString stringWithContentsOfURL:url encoding:NSASCIIStringEncoding error:nil];

    if (responseString) {
        NSArray *players = [responseString componentsSeparatedByString:@";"];

        NSUInteger LOOP_LIMIT = 100, count = 0;

        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        NSManagedObjectContext *context = [[AppController sharedAppController] managedObjectContext];
        [context setUndoManager:nil];

        for (int i=0; i<([players count] - 1); i++) {
            NSArray *info = [[players objectAtIndex:i] componentsSeparatedByString:@","];

            NSString *dateInfo = [info objectAtIndex:10];
            NSLocale *usLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease];
            NSDateFormatter *fo = [[[NSDateFormatter alloc] init] autorelease];
            [fo setDateFormat:@"MM/dd/yyyy"];
            [fo setLocale:usLocale];
            [fo setTimeZone:[NSTimeZone systemTimeZone]];
            NSDate *dob = [fo dateFromString:dateInfo];

            Players *player = [NSEntityDescription insertNewObjectForEntityForName:@"Players"
                                                            inManagedObjectContext:context];

            NSNumberFormatter *f = [[[NSNumberFormatter alloc] init] autorelease];
            [f setNumberStyle:NSNumberFormatterNoStyle];

            player.playerID = [f numberFromString:[info objectAtIndex:0]];              
            player.lastName = [info objectAtIndex:1];
            player.firstName = [info objectAtIndex:2];
            player.position = [info objectAtIndex:4];

            NSString *teamName = [info objectAtIndex:3];

            NSFetchRequest *req = [[[NSFetchRequest alloc] init] autorelease];

            NSEntityDescription *ent = [NSEntityDescription entityForName:@"Teams" inManagedObjectContext:context];
            [req setEntity:ent];
            [req setIncludesPropertyValues:NO];

            NSPredicate *pre = [NSPredicate predicateWithFormat:@"team=%@", teamName];
            [req setPredicate:pre];

            NSArray *list = [context executeFetchRequest:req error:nil];

            if ([list count]) {
                Teams *team = [list objectAtIndex:0];

                player.team_Players_Teams = team;
            }

            count++;

            if (count == LOOP_LIMIT) {
                [context save:nil];

                [context reset];

                [pool drain];

                pool = [[NSAutoreleasePool alloc] init];

                count = 0;
            }
        }

        if (count != 0) {
            NSLog(@"In Save Remaining");

            [context save:nil];

            [context reset];[pool drain];
        }

2 个答案:

答案 0 :(得分:0)

我看不到任何明显的泄漏但是:

  1. 您可以最小化alloc init retain NSLocaleNSDateFormatterNSNumberFormatter然后release使用的内存量循环完成后。这些似乎在循环运行之间没有变化。

  2. 我不知道核心数据,但NSManagedObject / Player *player对象的释放位置在哪里?这是通过Core Data自动释放的吗?

  3. 另外,您可以使用[list lastObject]而不是[list count][list objectAtIndex:0],因为如果列表为零,最后两个会崩溃

  4. 根据回复更新:

    如果没有任何结果可以产生影响,那么下一步就是简化代码,以便删除任何错误来源。

    1. 在上面的#1中执行我的建议,以尽量减少循环中的代码量。

    2. 检查您是否在某处释放list对象,或者将其分配为自动释放。

    3. 删除中间保存(count == LOOP_LIMIT内的所有代码),只有在处理完所有数组后才保存并排空池。您也不应该在if (count != 0)

    4. 内部使用以下代码
    5. error:nil语句替换为正确的error:&&error并记录错误。要记录错误,请执行以下操作(道歉但代码格式似乎不起作用 - 不明白为什么): NSError *error = nil; //Declared upfront

      // Your streamlined code

      // ....

      error = nil; //Just before a fetchRequest or context:save

      /* After looping through all your code now attempt to save */

      if(![context save:&error]) {

      NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
      NSArray *detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
      if(detailedErrors != nil && [detailedErrors count] > 0) {
          for(NSError *detailedError in detailedErrors) {
              NSLog(@"DetailedError: %@", [detailedError userInfo]);
          }
      } else {
          NSLog(@" %@", [error userInfo]);
      }
      

      }

    6. 然后检查日志以查看您是否收到任何奇怪的消息。您还可以在核心数据中的任何位置使用类似的代码来检查错误(即executeFetchRequest)。值得一试,找出错误在这里。

答案 1 :(得分:0)

我在代码中也看不到任何狡猾的东西。绝对没有错误出现在日志中?

用于导入数据的Core Data pdf中涵盖的另一个优化提示是将谓词创建移出循环并使用替换变量。