【问题标题】:Core Data Import Failure核心数据导入失败
【发布时间】:2011-06-23 14:50:09
【问题描述】:

我正在尝试将一个大型数据集(约 6,000 个)导入我的核心数据应用程序。我已阅读 Apple 文档“Efficiently Importing Data”,我认为我设置正确。奇怪的是应用程序并没有在模拟器中崩溃,尽管如果我使用 Leaks 仪器运行它会崩溃,但它并没有保存所有数据。有时它只能保存 3-400 次,有时它会保存 3-4000 次,而且很少保存整个数据集。我认为这可能与内存泄漏有关,而且我对使用 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];
        }

【问题讨论】:

  • [pool drain] 结尾缺失
  • True - 我刚刚添加了这一点,但这不应该影响实际的导入。导入过程中仍然存在一些错误。

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


【解决方案1】:

我也看不出代码中有任何可疑之处。日志中确定没有错误出现?

顺便说一句,Core Data pdf 中介绍的另一个用于导入数据的优化技巧是将谓词创建移到循环之外并使用替换变量。

【讨论】:

  • 没有没有得到任何错误。我终于通过将 LOOP_LIMIT 提高到 10000 来完成它的工作。它现在每次都可以在模拟器和设备上工作,但不能在仪器上工作。幸运的是,这只是应用程序的初始启动,所以我认为这不是问题。
  • 上面的编辑更改为 1,000 而不是 10,000。
【解决方案2】:

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

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

  2. 我不知道 Core Data 但NSManagedObject/Player *player 对象在哪里被释放?这是通过 Core Data 自动发布的吗?

  3. 顺便说一句,您可以使用[list lastObject] 而不是[list count][list objectAtIndex:0],因为如果列表为零,最后两个将崩溃

根据响应更新:

如果没有任何影响,那么下一步就是简化代码以消除任何错误来源。

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

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

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

  4. 用正确的error:&amp;&amp;error 替换error:nil 语句并记录错误。要记录错误,请执行以下操作(抱歉,代码格式似乎不起作用 - 不知道为什么): 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:&amp;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]);
    }
    

    }

  5. 然后检查日志以查看是否收到任何奇怪的消息。您还可以在需要检查错误的 Core Data 中的任何地方使用类似的代码(即executeFetchRequest)。值得一试以找出错误所在。

【讨论】:

  • 我相信 NSManagedObject 播放器应该与池一起发布。不幸的是它仍然崩溃,我不知道为什么。
  • 用更多选项和 cmets 更新了我的原始回复。我已经删除了我以前的 cmets,因为它们太小而无法阅读代码
猜你喜欢
  • 2013-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 2017-07-22
  • 2012-08-17
相关资源
最近更新 更多