核心数据多项目编辑效率和随机误差

时间:2013-01-14 13:17:40

标签: ios core-data

我希望这不是一个重复的问题。我似乎找不到类似的东西。大多数核心数据问题似乎都与创建新对象有关......

我的程序包含大约23,000个项目的数据库。我正在尝试创建导出/导入功能以将数据发送到其他设备(不与iCloud链接)。

导出工作正常,电子邮件......

我有导入功能,但功能很慢(稍后会更多,iPhone 5或iPad 3似乎不能正常工作)

我有一个函数解析我导入的数据到NSArray(_importedRows),然后运行以下代码:

self.managedObjectContext = [(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];

    NSManagedObjectContext *ctx = self.managedObjectContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"CHECKLIST"
                                   inManagedObjectContext:ctx];
    [fetchRequest setEntity:entity];
    ImportedData *importedData;
    NSString *verify;
    NSError *error = nil;
    NSManagedObject *updatedObject;
    NSArray *matchingItems;
    for (int i = 0; i < [_importedRows count]; i++) {
        importedData = [_importedRows objectAtIndex:i];
        verify = importedData.uniqueID;
        [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"uniqueID == %@", verify]];
        [fetchRequest setFetchLimit:1];
        matchingItems = [ctx executeFetchRequest:fetchRequest error:&error];

        for (updatedObject in matchingItems) {
            HUD.detailsLabelText = [NSString stringWithFormat:@"Updating %@" , [updatedObject valueForKey:@"figureName"]];
            [updatedObject setValue:importedData.numberOwned forKey:@"numberOwned"];
            [updatedObject setValue:importedData.numberWanted forKey:@"wishList"];
            [updatedObject setValue:importedData.availableTrade forKey:@"tradeList"];

        }

        [ctx save:&error];

        if (error != nil) {
            NSLog(@"error saving managed object context: %@", error);
        }

    }

基本上,我正在抓取一个核心数据实体,然后循环遍历我的数组检查匹配。当我找到匹配项(uniqueID谓词)时,我正在使用导入的数据更新对象。这段代码在我的iPhone 4s上工作正常,但速度很慢。 4,000件需要大约4-5分钟。我做了什么明显的错误?我应该更频繁地调用保存功能吗?

作为奖励,出于某种原因,当我在iPhone 5上测试它时,这个代码几乎不会起作用.10次中有9次(我的iPad 3上有50%的时间)我得到了

“1月14日08:06:44: * 由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:' - [__ NSCFSet addObject:]:尝试插入nil'”

在控制台中。想法?

如果需要更多详细信息,请与我们联系!

更新: 似乎handleOpenURL被调用了两次......一次在applicationdidfinishlaunching NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey]; if (url != nil && [url isFileURL]) { [self.window.rootViewController performSelector:@selector(showWithLabel:) withObject:url afterDelay:6]; }

并且在这里:

-(BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
  

{if(url!= nil&amp;&amp; [url isFileURL]){             [self.window.rootViewController performSelector:@selector(showWithLabel :) withObject:url];         }         返回YES;     }

我必须在app委托中使用这两个,否则函数将不会总是被调用(一次是在应用程序启动时,一次是应用程序已经在后台,我相信) - 我我添加了一个检查,以防止它在showWithLabel线程中第二次启动,但它似乎不是一个非常优雅的解决方案......

更新:@mundi建议清理fetchedresults代码,如下所示:

NSArray *importedIDs = [_importedRows valueForKeyPath:@"uniqueID"];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    fetchRequest.entity = [NSEntityDescription entityForName:@"CHECKLIST"
                                      inManagedObjectContext:ctx];
    fetchRequest.predicate = [NSPredicate predicateWithFormat:
                              @"uniqueID in %@", importedIDs];

    NSError *error = nil;
    NSManagedObject *updatedObject;
    NSArray *matchingItems;
    matchingItems = [ctx executeFetchRequest:fetchRequest error:&error];
    ImportedData *importedData;
    for (int i = 0; i < [_importedRows count]; i++) {
        importedData = [_importedRows objectAtIndex:i];
        for (updatedObject in matchingItems) {
            if ([importedData.uniqueID isEqualToString:[updatedObject valueForKey:@"uniqueID"]]) {
                HUD.detailsLabelText = [NSString stringWithFormat:@"Updating %@" , [updatedObject valueForKey:@"figureName"]];
                [updatedObject setValue:importedData.numberOwned forKey:@"numberOwned"];
                [updatedObject setValue:importedData.numberWanted forKey:@"wishList"];
                [updatedObject setValue:importedData.availableTrade forKey:@"tradeList"];
            }


        }
    }


    [ctx save:&error];

我确信它仍然可以更清洁一点,实际的更新部分(我不知道除了将fetchedresults中的每个项目与初始数组中的每个项目进行比较以确保它们更新之外怎么做正确的,但合并的取样结果极大地提高了速度(最初为4000件,现在在80-120秒之间为240秒)

首先对数组进行排序,然后按顺序进行更新,以便再次加速:

NSArray *matchingItemsSorted;
    matchingItemsSorted = [matchingItems sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
        NSString *first = [a valueForKey:@"uniqueID"];
        NSString *second = [b valueForKey:@"uniqueID"];
        return [first caseInsensitiveCompare:second];
    }];


    NSArray *importedRowsSorted;
    importedRowsSorted = [_importedRows sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
        NSString *first = [a valueForKeyPath:@"uniqueID"];
        NSString *second = [b valueForKeyPath:@"uniqueID"];
        return [first caseInsensitiveCompare:second];
    }];

    int i = 0;
    for (updatedObject in matchingItemsSorted) {
        NSLog(@"do we match? %@  :  %@", [[importedRowsSorted objectAtIndex:i] valueForKeyPath:@"uniqueID"], [updatedObject valueForKey:@"uniqueID"]);
        HUD.detailsLabelText = [NSString stringWithFormat:@"Updating %@" , [updatedObject valueForKey:@"figureName"]];
        [updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:@"numberOwned"] forKey:@"numberOwned"];
        [updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:@"numberWanted"] forKey:@"wishList"];
        [updatedObject setValue:[[importedRowsSorted objectAtIndex:i] valueForKeyPath:@"availableTrade"] forKey:@"tradeList"];
        i++;


    }

对于拥有nslog的4000个项目大约13秒左右...现在唯一奇怪的事情是,当我注释掉nslog时,它经常崩溃......它发生的速度如此之快以至于它正在破坏核心数据 - 当它没有不会崩溃,只需要4秒钟?

谢谢, 扎克

1 个答案:

答案 0 :(得分:1)

您有两个嵌套循环。使用此模式加快速度:

NSArray *importedIDs = [_importedRows valueForKeyPath:@"uniqueID"];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest.entity = [NSEntityDescription entityForName:@"CHECKLIST"
                                  inManagedObjectContext:ctx];
fetchRequest.predicate = [NSPredicate predicateWithFormat:
            @"uniqueID in %@", importedIDs];

像这样你可以获取一个包含所有匹配项的数组。