2

バックグラウンド

  • マルチスレッドCoreDataアプリケーション

  • NSTreeControllerNSOutlineViewバインディング付き

  • バックグラウンドコンテキストでNSOperationに子オブジェクトを作成します

  • を使用してメインコンテキストにマージしますmergeChangesFromContextDidSaveNotification

データ・モデル

問題

  • 20個の子の作成操作をキューに入れると、マージが完了すると、アウトラインビューに約10〜15個の子オブジェクトしか表示されません。

  • 最大同時操作を1に設定すると、完全に機能し、20人の子が表示されます。

質問

私がやろうとしていることは不可能ですか?コアデータがマージを正常に実行するのにどのように苦労するかがわかります。または、私のコードに問題がありますか?

コード

JGGroupController

 -(id)init {
     self = [super init];
     queue = [[NSOperationQueue alloc] init];
     [queue setMaxConcurrentOperationCount:10]; // If this is 1, it works like a dream. Anything higher and it bombs.
     return self;
 }

 -(IBAction)addTrainingEntryChild:(id)sender {
     moc  = [[NSApp delegate] managedObjectContext];
     JGTrainingBase *groupToAddTo = [[tree selectedObjects] objectAtIndex:0];
     for (NSUInteger i = 0; i < 20; i++) {
         JGAddChildrenObjectOperation    *addOperation = [[JGAddChildrenObjectOperation alloc] init]; 
         [addOperation addChildObjectToGroup:[groupToAddTo objectID]];
         [queue addOperation:addOperation];
     }
 }

JGAddChildrenObjectOperation-NSOperationサブクラス

 -(id)addChildObjectToGroup:(NSManagedObjectID *)groupToAddToID_ {
     groupToAddToObjectID = groupToAddToID_;
     return self;
 }

 -(void)main {
     [self startOperation];
     JGTrainingBase *groupToAddTo    = (JGTrainingBase *)[imoc objectWithID:groupToAddToObjectID];
     JGTrainingBase *entryChildToAdd = [JGTrainingBase insertInManagedObjectContext:imoc];
     [groupToAddTo addChildren:[NSSet setWithObject:entryChildToAdd]];
     [imoc save];
 [self cleanup];
     [self finishOperation];
 }

 -(void)mergeChanges:(NSNotification *)notification {
     NSManagedObjectContext *mainContext = [[NSApp delegate] managedObjectContext];
     [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                                   withObject:notification
                                waitUntilDone:YES];  
 }


 -(void)startOperation {
            // Omitted - Manage isExecuting, isPaused, isFinished etc flags

     imoc = [[NSManagedObjectContext alloc] init];
     [imoc setPersistentStoreCoordinator:[[NSApp delegate] persistentStoreCoordinator]];
     [imoc setUndoManager:nil];
     [imoc setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
     [imoc setStalenessInterval:0];

     [[NSNotificationCenter defaultCenter] addObserver:self
                                              selector:@selector(mergeChanges:) 
                                                  name:NSManagedObjectContextDidSaveNotification 
                                                object:imoc];
 }

 -(void)finishOperation {
            // Omitted - Manage isExecuting, isPaused, isFinished etc flags
 }
4

1 に答える 1

1

オペレーションでは、ストアとは異なる「バージョン」のエンティティを使用しています。次の操作順序を検討してください。

2つの操作を作成し、それらをO:FおよびO:Gと呼びます。これらは、子FおよびGをグループ1に追加し、子エントリセット[A、B、C、D、E]を持つG:1として示されます。

操作キューは、O:FとO:Gを同時にデキューするため、両方とも管理対象オブジェクトコンテキストとエンティティG:1をフェッチします。

O:Fは、G:1の子を[A、B、C、D、E、F]に設定します。O:Gは、G:2の子を[A、B、C、D、E、G]に設定します。

どちらの操作が勝つかは関係ありません。[A、B、C、D、E、F]または[A、B、C、D、E、G]のいずれかになりますが、どちらも不正な値です。店舗。

CoreDataは、変更が古くなっているため、これらのスレッドの1つで楽観的ロックエラーをスローするはずです。しかし、私は間違っている可能性があります。

肝心なのは、オブジェクトの状態を同期せずに、スレッド間で同じオブジェクトを変更しているということです。20の操作を作成する代わりに、20のオブジェクトを追加する1つの操作を作成しますが、同期せずに複数のスレッドから同じオブジェクトを変更しようとするというアーキテクチャ上のコア問題があります。

それは毎回失敗します。

于 2010-11-14T02:45:46.887 に答える