0

私は 1000 の間隔で MOC を保存しようとしていますが、以下のコードではそれらの一部が欠けているようです。これにより、オブジェクトの 2/3 のみが保存され、残りは奈落の底に消えたように見えました。これは、これを達成するための非常に厄介な方法のように思えるので、誰かがより良い方法を提案できるなら、私はそれを聞きたい.

この方法でも、115,000 個のオブジェクトを追加するのに約 9 分かかります。これを改善するために私にできることはありますか?ありがとう。

dispatch_async(backgroundDispatchQueue,{

 NSManagedObjectContext *backgroundThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
 [backgroundThreadContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
 [backgroundThreadContext setUndoManager:nil];


 [products enumerateObjectsUsingBlock:^(id product, NSUInteger idx, BOOL *stop) {


   NSManagedObject* newProduct;
   newProduct = [NSEntityDescription insertNewObjectForEntityForName:@"Products" inManagedObjectContext:backgroundThreadContext];

   [newProduct setValue:[product valueForKey:@"product_name"] forKey:@"name"];
   [newProduct setValue:[product valueForKey:@"product_codes"] forKey:@"codes"];

   if ([product valueForKey:@"information"] == (id)[NSNull null]){
                                   // No information, NULL
     [newProduct setValue:@"" forKey:@"information"];
   } else {
     NSString *information = [product valueForKey:@"information"];
     [newProduct setValue:information forKey:@"information"];

   }

   if ([product valueForKey:@"megaimportant"] == (id)[NSNull null]){
                                       // No information, NULL
     [newProduct setValue:@"" forKey:@"megaimportant"];
   } else {
     NSString *megaimportant = [product valueForKey:@"megaimportant"];
     [newProduct setValue:megaimportant forKey:@"megaimportant"];

   }

   if ((self.productDBCount % 1000) == 0){
     NSLog(@"SAVE ME");
     NSError *error;

     if(![backgroundThreadContext save:&error])
     {
       NSLog(@"There was a problem saving the context (add/update). With error: %@, and user info: %@",
         [error localizedDescription],
         [error userInfo]);
     }
   } else if ((self.productDBCount + 1) == self.totalCount){
     NSLog(@"Final Save");

     NSError *error;

     if(![backgroundThreadContext save:&error])
     {
       NSLog(@"There was a problem saving the context (add/update). With error: %@, and user info: %@",
         [error localizedDescription],
         [error userInfo]);
     }
   }



   dispatch_async(dispatch_get_main_queue(), ^
   {

    self.productDBCount = self.productDBCount + 1;
    float progress = ((float)self.productDBCount / (float)self.totalCount);
    int percent = progress * 100.0f;
    self.downloadUpdateProgress.progress = progress;
    self.percentageComplete.text = [NSString stringWithFormat:@"%i", percent];
    NSLog(@"Added / updated product %f // ProductDBCount: %i // Percentage progress: %i // Total Count: %i", progress, self.productDBCount, percent, self.totalCount);

    NSDate *currentProcessedDate = [NSDate date];
    NSTimeInterval timeSinceStarted = [currentProcessedDate timeIntervalSinceDate:self.startProcessing];
    NSInteger remainingProcesses = self.totalCount - self.productDBCount;
    float timePerProcess = timeSinceStarted / (float)self.productDBCount;
    float remainingTime = timePerProcess * (float)remainingProcesses;
    self.timeRemaining.text = [NSString stringWithFormat:@"ETA: %0.0f minutes %0.0f seconds", (((float)remainingTime - fmodf(remainingTime, 60.0f))/60), fmodf(remainingTime, 60.0f)];

    if (self.productDBCount == self.totalCount){

      [self updatesCompleted:[jsonArray valueForKey:@"last_updated"]];
    }

                                                 });
}];

});
4

1 に答える 1

1

バックグラウンド キューでスケジュールしたブロックの最後に、メイン キューで別のブロックを非同期的にスケジュールします。そこで、self.productDBCount をインクリメントします。しかし同時に、バックグラウンド キューでこのプロパティを使用しています。

そのため、ループの次の反復でバックグラウンド ブロックの値がインクリメントされず (メイン キューのブロックがまだ実行されていないため)、それについて誤った決定を下す可能性があります。さらに悪いことに、このプロパティが非アトミックとして宣言されている場合、壊れた値を取得することさえあります (ただし、アトミックにしてもこの競合状態は解決されません)。

非同期呼び出しを同期呼び出しに置き換えてみてください。dispatch_sync(dispatch_get_main_queue()...

メモリ上でインポートを容易にするために、各バッチの保存後にコンテキストをリセットすることもできます。ただし、リセット後にこのコンテキストで作成したオブジェクトを使用しないようにする必要があります。

インポート中に最も時間がかかるものを確認したい場合は、Instruments で実行します。Core Data 機器と Time Profiler 機器の組み合わせをお勧めします。Core Data インストゥルメントは、シミュレーターでのみ使用できます。

于 2013-07-12T11:48:22.520 に答える