1

これが重複した質問でないことを願っています。似たようなものを見つけられないようです。ほとんどのコアデータに関する質問は、新しいオブジェクトの作成に関するものです...

約 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 でテストすると、ほとんど機能しません。

「1 月 14 日 08:06:44 : *キャッチされない例外 'NSInvalidArgumentException' が原因でアプリを終了しています。理由: '-[__NSCFSet addObject:]: nil を挿入しようとしています'」

コンソールで。考え?

詳細が必要な場合はお知らせください。

更新: handleOpenURL が 2 回呼び出されているようです... アプリケーションで 1 回は起動を終了しました 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 && [url isFileURL]) { [self.window.rootViewController performSelector:@selector(showWithLabel:) withObject:url]; はいを返します。}

アプリのデリゲートでこれらの両方をラベリングする必要があります。そうしないと、関数が常に呼び出されるとは限りません (1 回はアプリケーションの起動時で、1 回はアプリケーションが既にバックグラウンドにあると思います)。 showWithLabel スレッド内で 2 回目の起動を防止するようにチェックしますが、それは非常にエレガントな解決策ではないようです...

更新: @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 の各項目を初期配列の各項目と比較して、それらが正しく更新されていることを確認する以外の方法はわかりませんが、 fetchedresults を組み合わせると、速度が大幅に向上しました (元は 4000 アイテムで 240 秒でしたが、現在は 80 ~ 120 秒です)。

最初に配列をソートし、次に順番に更新すると、再び大幅に高速化されます。

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秒しかかかりませんか?

ありがとう、ザック

4

1 に答える 1

1

ネストされたループが 2 つあります。これを高速化するには、次のパターンを使用します。

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

このように、一致するすべてのアイテムを含む 1 つの配列を取得できます。

于 2013-01-15T11:43:12.817 に答える