ios - coredata swift 入門




NSFetchedResultsControllerは別のコンテキストからの更新を表示しません (2)

あなたは基本的な考え方を持っているので、あなたのコードのどこかにおそらくバグがあります...

バックグラウンドMOCから通知を受け取るために正しく登録していることを再度確認します。

すべてのオブジェクトからすべての通知を受け取るために登録します。 その方法では、イベントとそのすべてのデータを記録します。 オブジェクトがMOCの場合は、すべてのプロパティ(特に、登録、挿入、更新、および削除されたオブジェクトのリスト)をダンプします。

保存呼び出しの前と後でログ・ステートメントを入れ、通知をマージするための通知ハンドラに入れます。

また、多くのコードを省略したので、実際に何をしているのか分かりませんが、コードサンプルはisSyncをYESに設定して読み込み中のすべてのオブジェクトが難しいようですが、フェッチ要求ではisSyncいいえ。 それらの新しいオブジェクトのどれもその述語を渡すことはありません。

最後に、モデル定義を再度確認し、正しい番号タイプを使用していることを確認してください。 これは大きな問題の原因となる可能性があります。

EDIT

ええ、忘れました...フェッチ要求にソート記述子がありません。 FRCを作成するとき、フェッチ要求には少なくとも1つのソート記述子が含まれていなければなりません。複数のセクションがある場合は、最初のソート記述子を使用してオブジェクトをセクションにグループ化します。

アレクサンドルのコメントにフォローアップする...私は私の記事の冒頭でそれを暗唱しましたが、あなたがMOCからの通知を聞きたくないのは確かです。デバッグ目的のためだけにロギングします)。 使用しているMOCについて知っておく必要があります。

さらに、このタイプの処理には親/子MOCを使用することをお勧めしますが、正しく実行された場合は、何をしているのかを確認する必要があります。

親(プライベート同時実行型)Main(メイン同時実行型)

そして、あなたのバックグラウンドMOCを使って、メインMOCを親として設定させるだけです。 それらが保存されると、それらのオブジェクトはメインのMOCに直接注入されます。 メインのMOCは、後でそれらをディスクに置くためにセーブを発行することができます。

または、親のMOCを親として、親のMOCがフェッチを再発行して親からデータを取得するだけでも構いません。

私はNSFetchedResultsControllerを持っていて、いくつかの操作はNSOperationQueueを介して別々のスレッドで管理オブジェクトを更新します。

FRC(述語付き)は次のようになります。

- (NSFetchedResultsController*)fetchedResultsController
{
    if(fetchedResultsController) return fetchedResultsController;

    NSManagedObjectContext* mainContext = [self managedObjectContext];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[NSEntityDescription entityForName:@"Check" inManagedObjectContext:mainContext]];
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"isSync == %@", [NSNumber numberWithBool:NO]]];
    [fetchRequest setFetchBatchSize:10];

    fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
    fetchedResultsController.delegate = self;

    [fetchRequest release], fetchRequest = nil;

    return fetchedResultsController;
}

メインスレッドとスレッド化された操作には、独自の管理オブジェクトコンテキストがあります。 彼らは同じコーディネーターしか共有しません。

スレッド操作では、 isSyncプロパティをNOからYESに変更します。 更新するエンティティをCheckするには、メインコンテキストをNSManagedObjectIDスレッドにNSManagedObjectIDます。 threaded操作は、次のように管理対象オブジェクトを取得します。

-(void)main
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSManagedObjectContext *exportContext = [[NSManagedObjectContext alloc] init];
    [exportContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];

    //...

    Check* check = (Check*)[exportContext existingObjectWithID:objID error:&error];
    check.isSync = [NSNumber numberWithBool:YES];

    //...

    [exportContext save:&error];

    [pool release], pool = nil;
}

スレッド操作がsave呼び出すと、 mergeChangesFromContextDidSaveNotification通知が呼び出され、メインコンテキストによって変更がマージされます。

- (void)contextChanged:(NSNotification*)notification
{
    if ([notification object] == [self managedObjectContext]) return;

    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
        return;
    }

    [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}

notificationの説明を記録すると、変更が正しく実行されたことが確認されます。

私の問題

NSFetchedResultsControllerDelegateデリゲートメソッドは呼び出されません。

これは、同じコンテキスト(メインのもの)を扱うことが変更を待ち受けることができるため、メソッドが呼び出されること(例: UITableView内の行オブジェクトの削除)が非常に奇妙です。

私は同じ問題を持っているので、SOに関するいくつかの話題を見つけました。 私はすべての回避策を試しましたが、私は貴重な解決策を見つけることができません:

  1. NSFetchedResultsControllerが他のコンテキストからの更新を表示しない

  2. NSFetchedResultsControllerはバックグラウンドスレッドからのマージ後にデリゲートメソッドを起動しません

  3. NSFetchedResultsControllerは、異なるNSManagedObjectContextからマージされた変更を無視します。

前もって感謝します。

編集

上記のコードは以前のモデルで動作していました。 それから、以前のモデルから新しいモデルをコピーして貼り付けましたが、もう動作しません。

提案?

編集2

これはNSFetchedResultsController getterで使用している述語です。 それは私のせいですが、私が投稿したときに私はそれをコピーしませんでした。

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"insertionDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

// previous code here
[fetchRequest setSortDescriptors:sortDescriptors];

さて、 Jodyについての最後のコメント

NSOperationのmain()では、新しいオブジェクトを読み込みます。新しいオブジェクトごとにisSyncをYESに設定しているように見えます。 fetchedResultsControllerに使用する述部はisSync == NOを持つオブジェクトのみを探します。

私は、プロパティisSyncがYESに設定されていると、 NSFetchedResultsControllerその変更を観察して、述語と一致しない行を削除することを期待しています。 私が間違っている?

バックグラウンドからメインスレッドへの変更をマージするとき、 isSyncプロパティを更新したオブジェクトはほとんどないことがisSyncます。


私はちょうど同じ問題を抱えていました。私は親子関係で解決しました。 ここに私が持っていた問題があります。

独自のmanagedObjectContext (必須)を持つバックグラウンドスレッドでCore Dataオブジェクトグラフを更新していましたが、私のfetchedResultsControllerはデータベースに対して行った変更をfetchedResultsControllerできませんでした。

私はそれを解決した後、私はいくつかのメモを取った:

ManagedObjectContextはスレッドセーフではないため、 managedObjectContextを他のスレッドと共有することはできません。 スレッドがmanagedObjectContextを使用する必要がある場合、スレッドは独自のmanagedObjectContextを初期化します。

managedObjectContextを初期化するには、次の2つの方法があります。

  • alloc/initを実行し、 persistentStoreCoordinatorプロパティを設定します。

  • alloc/init次にparentContextプロパティの代わりにparentContextプロパティを設定する

注: parentContextプロパティとparentContextプロパティの両方を設定することはできません。

コンテキストが主スレッドでのみ使用する必要のあるコントローラとUIオブジェクトにリンクされているバックグラウンドスレッド(コアデータドキュメント)で実行される場合、親子コンテキストを使用する必要があります

親子コンテキストに必要な要件は次のとおりです。

  • 親コンテキストはメインスレッドに存在する

  • 子のコンテキストはバックグラウンドスレッドに存在する

  • 両方のコンテキストをinitWithConcurrencyType:NSMainQueueConcurrencyTypeメソッドで初期化する必要があります。

  • 変更のバッチが子コンテキストで実行されたとき、両方のコンテキストは保存操作を実行する必要があります。 これらの保存操作は、performBlockメソッドにネストする必要があります。

    childContext performBlock:^{
        [childContext save:nil];
        [self.parentContext performBlock:^{
            [self.parentContext save:nil];                
        }];
    }];
    

編集:上のコードは実際には2つの理由で悪い考えです:

1)親コンテキストを保存せずに動作します。

2)親コンテキストが実行されている場合、メインスレッドはブロックされます。

私はそれが助けて欲しい!

編集:ここで私を大きく助けたスレッドです: コアデータ親のManagedObjectContextは、子コンテキストとの同時性の型を共有する必要がありますか?







nsoperationqueue