1

UIManagedDocumentには、NSFetchedResultsControllerを使用してリストに表示するデータがあります。データはバックグラウンドで定期的に更新され、変更はUIManagedDocument.managedObjectContextに(performBlockを使用して)適用されます。子コンテキストでNSFe​​tchedResultsControllerをフェッチできません

ドキュメントのメインコンテキストからデータを表示すると、すべて正常に動作します。しかし、すぐに、私はメインのコンテキスト(child.parentContext = document.managedObjectContext)の子であるコンテキストでリストを表示するように、私は、任意のオブジェクトが表示されないと、次のエラーがコンソールに出力されます。

foo[17895:15203] CoreData: error: (NSFetchedResultsController) 
       The fetched object at index 5 has an out of order section name 'E. 
       Objects must be sorted by section name' 

にのみ発生します新しいオブジェクトが文書の連絡先に挿入された後。自動保存が実行されるのを待つと、リストが正常に表示されます。また、問題は私がNSFetchedResultsControllerに設定した子コンテキストでのみsectionNameKeyPathが設定されている場合です。

これは私のセットアップフェッチ結果コントローラ、私は私が間違ってここに何ができるかを見ていないので、派手な何がどのようである:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Contact"]; 
fetchRequest.sortDescriptors = [Contact userDefinedSortDescriptors]; 
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"hidden == nil || hidden == NO"]; 

NSFetchedResultsController *fetchedResultsController = 
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
            managedObjectContext:_managedObjectContext 
             sectionNameKeyPath:[Contact userDefinedSectionNameKeyPath] 
               cacheName:@"ContactList"]; 

[Contact userDefinedSortDescriptors][Contact userDefinedSectionNameKeyPath]実行時に解決されています。ソート記述子には、最初のエントリとしてsectionNameKeyPathが含まれています。どちらもnilやその他の面白いものはありません。

:曖昧な部分を明確にしました。具体的には、ドキュメントの管理オブジェクトコンテキストで-save:を呼び出さない。

編集2:MOCが互いにどのように関係しているかを説明しようとします。

1)ドキュメントをロードすることによって作成されたUIManagedDocument.managedObjectContext

は、劇中の3つの管理対象オブジェクトコンテキストがあります。

2)オブジェクトを時折更新するバックグラウンドスレッドが実行されています。

context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
context.parentContext = repository.managedObjectContext; 

[context performBlock:^{ /* updates */ }]; 
[context performBlock:^{ [context save:NULL]; }]; 

3)ユーザーが新しいMOCは、文書MOCの子として作成された変更を行いたい:これは親としての文書MOCとプライベートキューMOCです。これはメインキューMOCです。上記のフェッチを実行するために使用されるコンテキストです。

バックグラウンド更新はNSOperationQueueから実行されますが、バックグラウンドMOCへのすべてのアクセスは適切に-performBlock:で囲まれています。他のすべてのアクセスはメインスレッドから行われます。

編集3NSFetchRequestにいくつかの設定で遊んでいる間、私はfetchRequest.includesPendingChanges = NOを設定するときに問題が消えることがわかりました。しかし、これは実行可能な解決策ではありません。なぜなら、UIManagedDocumentによって変更がバックグラウンドで保存されるまで、ユーザは更新をもう見ないからです。

+0

複数のコンテキストは扱いにくいです。したがって、あなたの_managedObjectContextはドキュメントのメインMOCの子ですか?どのコンテキストにオブジェクトを挿入していますか?また、setShouldRefreshRefetchedObjectsと、フェッチが実際にオブジェクトを取得する方法を決定するその他のフェッチプロパティを見てください。 –

+0

_managedObjectContextは、メインMOCまたはメインMOCの子であり、コントローラのロード方法に応じて異なります。それが主なMOCであるときはすべて正常ですが、それが子供の場合は、私が説明した問題が発生します。他の子MOCにオブジェクトを挿入し、完了したらこの子を保存します。 – Alfonso

+0

また、shouldRefreshRefetchedObjectsをYESに設定しようとしましたが、動作しませんでした。ほとんどの場合、変更はメインMOCに適用された後(メインMOCが保存される前)にフェッチが行われるため、影響はありません。 – Alfonso

答えて

4

私にはいくつかの赤い旗があります。まず、これ...

データはバックグラウンドで定期的に更新され、変更はUIManagedDocument.managedObjectContext(performBlock :)を使用して保存されます。

UIManagedDocumentsは自動保存を実装しており、保存メソッドを直接呼び出す必要があるのは最初の作成時です。他のすべての「保存」は、自動保存インターフェースを介して行う必要があります。基本的には、それは呼び出すだろう

[document updateChangeCount:UIDocumentChangeDone]; 

これはUndoManagerを使用すると自動的に行われます。したがって、document.managedContextに直接フィードしている場合は、上記のメソッドを呼び出して、管理されたドキュメントに変更が行われたことを通知し、それ以外はすべて自動的に処理する必要があります。

しかし、すぐに私は子供のコンテキストでリストを表示するよう、

何の子コンテキスト:

第二には、私はあなたがこれで何を意味するかわからないんだけど?なぜ任意の文脈に何かが見えるべきですか?それは、UIManagedDocument、または親の主なコンテキストの子コンテキストか、それとも何か他のコンテキストですか?

ドキュメントは明確です(いくつかの明確な定義がありますが)残念ながら、UIDocument、UIManagedDocument、およびすべてのNSManagedOjectContextのドキュメントセットを読む必要があります。

私は最終的に何が起こっていたのか(皮肉なことに、iCloudの仕組みを読んで)、私の頭の中を包み込むと、UIManagedDocumentに関連するすべての問題が消えてしまったようです。

は基本的には、これらの単純なルールに従う:

  1. はUIManagedDocumentに埋め込まれた任意のコンテキストに直接任意の「保存」メソッドを呼び出すことはありません。

  2. オブジェクトが「ダーティ」で保存する必要がある場合は、変更をUNDOマネージャに登録するか、[doc updateChangeCount:UIDocumentChangeDone]を直接呼び出すかのどちらかです。

  3. 子のコンテキストを使用する場合は、先に進んでください。この場合は、parentContextプロパティを設定し、子コンテキストでsave:を呼び出します。他のすべては自動的に起こります。

EDIT 別の赤い旗を使用すると、異なるコンテキストを使用してコードを実行していることです。そのような場合は、正しいスレッドから実行していることを確認する必要があります。 NSManagedObjectContextオブジェクトはスレッドセーフではありません。したがって、それらは、それらが作成されたスレッド(NSConfinementConcurrencyTypeの場合)から常にアクセスされなければならず、他の2つの並行性タイプのいずれかがperformBlockを使用している必要があります。

複数のコンテキストを使用して連続的に挿入/フェッチしている場合は、解決すべきいくつかの問題があります。主に、変更を伝播して保存するようスケジュールを設定してから、フェッチが実行したいことを実行する必要があります。

挿入が完了したら、必ずUIManagedDocumentの子コンテキストでsaveを呼び出してください。管理対象ドキュメントでsaveまたはsaveToURLを呼び出さないでください。上記の方法で保存してください。これにより、変更が正しく伝播されます。

フェッチするときに、フェッチをコンテキストのチェーンの上に移動するかどうかを決定する必要があります。NSFetchRequestには(setShouldRefreshRefetchedObjectsのような)たくさんのオプションがあります。これらのオプションは、フェッチが独自のコンテキストを使用するのか、バッキングストアに行くのか、他の多くのものを決定します。デフォルトはほとんどの時間に欲しいものですが、子のコンテキストを使用するときは、より多くの責任があります。

また、子コンテキストを持っている場合は、正しい並行性タイプで作成し、正しいスレッド/キュー内でのみ使用していることを確認する必要があります。それ以外の場合は、未定義の結果が得られます。最近の質問の編集から、この声明を受けて

EDIT

3)ユーザーが新しいMOCは、文書のMOCの子として作成された変更を行いたいと考えています。これはメインキューMOCです。上記のフェッチを実行するために使用されるコンテキストです。

私はこれをやったことがないし、私には別の赤旗です。すでにメインキューMOCがあります。これはdocument.managedObjectContextです。メインスレッドの文書に悩まされる場合は、これを使用します。覚えておいても、CoreDataは依然としてスレッド包含モデルで動作し、スレッドごとに1つのMOCしか必要としません。新しいAPIは、MOCをキューに関連付ける方法を提供し、役立ちますが、スレッドごとに複数のMOCを持つと問題が発生する可能性があります。一般的に、私はそれを避けるだろう。

+0

ありがとうございます。私はいくつかのあなたの点に対処するために質問を更新しました。私は呼び出していません - 保存:mocで、子のコンテキストからのみ。私は決して-updateChangeCount:を呼び出すことはないので、これが私の問題を解決するかどうかを調べるつもりです。 – Alfonso

+0

私は-updateChangeCountを使ってみました:しかし、悲しいことには役に立ちません。 – Alfonso

+0

includesPendingChangesをNOに設定すると、エラーは表示されなくなりますが、更新が保存されるまで表示されません。私はcontextを-processPendingChangesを送信して処理するように強制しようとしましたが、それは役に立たないようです。 – Alfonso

関連する問題