5

私は Marcus Zarra の Core Data ブックのマルチスレッドに関する章を読み、彼のサンプル コードをかなり詳しく調べました。しかし、彼のコードや他の場所で見つけた他のコードは、お互いを認識する必要のないバックグラウンド プロセスに焦点を当てているようです。これらの例は、ツリー構造のインポートには適していますが、有向非巡回グラフのような、より一般的な (複雑な) 構造のインポートには対応していません。

私の場合、C++ クラス階層を解析しようとしており、できるだけ多くの NSOperations を使用したいと考えています。遭遇したクラスごとに NSManagedObject インスタンスを作成し、保存されるたびに異なる NSManagedObjectContexts をマージしたいと考えています。

余談ですが、ファイルを繰り返し処理し、一度に 1 つずつ解析する単一の NSOperation で動作させることができます。この実装では、メイン スレッドの MOC で -mergeChangesFromContextDidSaveNotification: を呼び出す -mergeChanges: アプローチがうまく機能します。

しかし、理想的には、1 つの NSOperation でソース ファイルを反復処理し、NSOperations を生成して各ファイルを解析します。私はいくつかのアプローチを試みましたが、うまくいかないようです。最も有望なのは、各 NSOperation が NSManagedObjectContextDidSaveNotification を監視するようにすることでした。-mergeChanges: を使用すると、次のようになります。

- (void) mergeChanges:(NSNotification *)notification
 {
 // If locally originated, then trigger main thread to merge.
 if ([notification object] == [self managedObjectContext])
  {
  AppDelegate *appDelegate = (AppDelegate*)[[NSApplication sharedApplication] delegate];
  NSManagedObjectContext *mainContext = [appDelegate managedObjectContext];

  // Merge changes into the main context on the main thread
  [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
         withObject:notification
         waitUntilDone:YES];
  return;
  }
   // If not locally originated, then flag need to merge with in this NSOperation's thread.  
 [self setNeedsToMerge:YES];
 [self setMergeNotification:notification];
 }

基本的に、解析中の NSOperation の main() は ivar 'needsToMerge' を定期的にチェックしていました。true の場合、-mergeChangesFromContextDidSaveNotification: は、キャッシュされた NSNotifications を使用してローカル MOC で呼び出されました。そして、needsToMerge がリセットされました。通知がローカルで発生した場合、メイン スレッドはその MOC で -mergeChangesFromContextDidSaveNotification: を実行するように指示されました。

これが機能しなかった理由と、これが得られた理由があると確信しています。

警告: 呼び出しをキャンセルしています - 現在のスレッドのスタック上の objc コードにより、これは安全ではなくなります。

また、NSPeristentStoreCoordinator のロックを使用してアクセスを制御しようとしましたが、NSManagedObjectContext の -save: メソッドの呼び出し中にロックが保持されると問題が発生します。なぜなら、-save: は関心のあるオブザーバーに保存イベントを通知し、-mergeChangesFromContextDidSaveNotification: の取得をブロックしているように見えるからです。 PSCのロック。

これはずっと簡単なはずです。

4

2 に答える 2

0

この 2 つのコードは、アプリケーションで正しく機能するようになりました。

- (void)mergeChanges:(NSNotification *)notification;
{
//AppDelegate *appDelegate = [[NSApplication sharedApplication] delegate];
NSManagedObjectContext *mainContext = [appDelegate managedObjectContext];

// Merge changes into the main context on the main thread
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
                              withObject:notification
                           waitUntilDone:YES];  
}

-(void) main {
// Register context with the notification center
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
[nc addObserver:self
       selector:@selector(mergeChanges:) 
           name:NSManagedObjectContextDidSaveNotification
         object:managedObjectContext];

もちろん、managedObjectContext の意味は次のとおりです。

managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:[appDelegate persistentStoreCoordinator]];
[managedObjectContext setUndoManager:nil];

メインモックから更新する前に何かを削除する必要がある場合は注意してください。同じ内容の他の変更をどこでも処理しているときにメインスレッドから moc を使用できないことを理解している間、私はクレイジーな時間と多くのデバッグが難しいエラーを抱えています。

于 2011-02-03T10:13:14.303 に答える