web-dev-qa-db-ja.com

NSFetchedResultsControllerがperformFetchでクラッシュする:キャッシュを使用する場合

NSFetchedResultsControllerを使用して、日付で区切られた一連のオブジェクトを表示します。新規インストールでは、すべてが完全に機能し、オブジェクトがテーブルビューに表示されます。しかし、アプリを再起動するとクラッシュするようです。 NSFetchedResultsControllerを初期化するときにキャッシュを指定し、そうでない場合は完全に機能します。

NSFetchedResultsControllerを作成する方法は次のとおりです。

- (NSFetchedResultsController *)results {
    // If we are not nil, stop here
    if (results != nil)
        return results;

    // Create the fetch request, entity and sort descriptors
    NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
    NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"utc_start" ascending:YES];
    NSArray *descriptors = [[NSArray alloc] initWithObjects:descriptor, nil];

    // Set properties on the fetch
    [fetch setEntity:entity];
    [fetch setSortDescriptors:descriptors];

    // Create a fresh fetched results controller
    NSFetchedResultsController *fetched = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"day" cacheName:@"Events"];
    fetched.delegate = self;
    self.results = fetched;

    // Release objects and return our controller
    [fetched release];
    [fetch release];
    [descriptor release];
    [descriptors release];
    return results;
}

これらは、アプリがクラッシュしたときに受け取るメッセージです。

FATAL ERROR: The persistent cache of section information does not match the current configuration.  You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'FATAL ERROR: The persistent cache of section information does not match the current configuration.  You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:'

私がこれを引き起こすような特別なことをしているとは思わないので、なぜそれがそれを言っているのかについて私には本当に手がかりがありません。唯一の潜在的な問題はセクションヘッダー(日)です。これは、新しいオブジェクトを作成するときに次のように構成します。

// Set the new format
[formatter setDateFormat:@"dd MMMM"];

// Set the day of the event
[event setValue:[formatter stringFromDate:[event valueForKey:@"utc_start"]] forKey:@"day"];

先に述べたように、キャッシュが含まれていない場合、これはすべて正常に機能します。助けてくれてありがとう!

47
Oliver

Appleが新しいiOS 4.0をリリースしたとき、私のアプリの1つに同様の問題がありました。検索:

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

そして、パラメーターcacheNameの値をnilに設定します。それは私のために働いた、あなたのためにそれが願っています。お知らせ下さい。

65
IssamTP

MacBook ProでSnow Leopard 10.6.4と最新のSDKにアップグレードすると、同じエラーが発生し始めました。

結局のところ、私たちの多くはルールに準拠していないコードを使用していましたが、CoreDataが実際に独自のルールに従って動作していないため、それを知りませんでした。

具体的には、取得したものがキャッシュされます。4.0では、以前のSDKでキャッシュが削除された場合、そのキャッシュは自動的には削除されません。

私にとって、解決策はシンプルでした。キャッシュを削除するクラスメソッドを使用しました。個々のエンティティを指定できますが、nilを指定して、この特定の起動コードですべてを実行します。

[NSFetchedResultsController deleteCacheWithName:nil];

突然、CoreDataに慣れるためだけに取り組んだ小さなアプリが再び動作するようになりました。

30
Mike V

NSFetchedResultsController のドキュメントから直接:

フェッチ要求の変更

フェッチリクエストを変更して結果を変更することはできません。フェッチ要求を変更する場合は、次のことを行う必要があります。

  1. キャッシュを使用している場合は、(deleteCacheWithName:)。通常、フェッチ要求を変更する場合は、キャッシュを使用しないでください。

  2. フェッチ要求を変更します。

  3. 呼び出しperformFetch:

15
Mark Adams

同様の問題が発生しました。デバッガーコンソールを調べたところ、キャッシュされたオブジェクトとフェッチされたオブジェクトが何であるかが示され、それらが矛盾している理由を突き止めることができました。私の場合、それは別の述語が原因でした。

私の述語の値は動的ではないため、述語ごとに異なるキャッシュ名を指定できます。これにより、指定した「タイプ」ごとにキャッシュが作成されます。

キャッシュの必要性を評価する必要があると思います。 nilを指定することは、すべての呼び出しでフェッチが行われることを意味します。

このエラーは、フェッチ要求に変更があった場合にのみ発生することがわかりました。新しいNSFetchRequest OR述語を変更するORソート記述子を作成する場合は、キャッシュを削除するか、別のキャッシュを使用する必要があります。それ以外の場合は、同じNSFetchRequestを持っているか、NSFetchedResultsControllerが保持されていることを確認して、問題を解決してください。

6
Terrence Tan

シミュレーターを使用している場合は、リセットしてみてください。エンティティマップを変更したため、残りのキャッシュが混乱していると思います。そうでない場合は、エラーが言うことを試すことができます:

- (void)applicationWillTerminate:(UIApplication *)application {
    [NSFetchedResultsController deleteCacheNamed:@"Events"];
    //etc
}
3
shosti

Xcode 7(ベータ4)でも例外は発生します。

キャッシュを無効にしたり、+ deleteCacheWithNameを使用したりせずに、NSFetchedResultsControllerのフェッチリクエスト、その述語、またはそのソート記述子を不正に変更しました:

注:これは変更されていないXcode "テンプレート" Master-Detail iOSアプリと標準のXcode CoreData "ボイラープレート"Xcode 7で作成され、最新の(iOS 9)展開ターゲットを使用して作成されたコード。

シミュレータでアプリを再起動したときに、最初に気が付きました。 Xcodeを使用してアプリを数回起動および停止していたところ、それが起こりました。そしてそれは起こり続けました。私はいくつかの実験を行うことにしました、そして結果:

  • シミュレーターでアプリを停止するたびに、その後の起動時に例外が発生しました。
  • シミュレーターのHomeボタンを使用してアプリを停止するたびに、再び正常に起動することができました。

問題は次のように修正であり、以下の方法の一方または他方を使用できます。

  • AppDelegateの_application didFinishLaunchingWithOptions_メソッドで、次のSwift NSFetchedResultsController.deleteCacheWithName(nil)またはObjective-C _[NSFetchedResultsController deleteCacheWithName:nil];_コードを追加します。これにより、破損したキャッシュがクリアされます。
  • シミュレータのSimulatorメニューからReset Content and Settingsを選択します。これで問題は解決しますが、テストデータが失われます

また、これはXcodeを介して実行し、クリーンアップする前にアプリを停止することのアーティファクトであると私は思います。実際のデバイスではこれを見たことがありません。

3
rholmes

最近同じ問題が発生した場合、問題はなんとかしてCore Dataがキャッシュをクリーンアップしないため、最初は正常に動作しますが、その後は動作しないことです。次に、NSFetchRequestを初期化した直後にこの行を挿入します

[NSFetchedResultsController deleteCacheWithName:@"Name"];
1
Vini Oliveira

ホームボタンを使用して、またはXcodeでアプリを終了して、シミュレータを終了しますか?たぶん、アプリがキャッシュへの書き込みを完了するための時間を取得していないのかもしれません。ホームボタンを使ってアプリを終了してみてください。

1
nevan king

私も同じ問題を抱えていました。
修正するために、[NSFetchedResultsController deleteCacheWithName:@"cacheName"]; resultsControllerの初期化の前。彼は初めてそこに行くだけなので、私にとってはうまくいきます。

1
pablotj

Ray Wenderlichで見つけた forums ということ

データストアに新しいものを追加したときにフェッチリクエストがまだ作成されていない場合にのみクラッシュすることに注意してください、つまりLocationsビューがまだロードされていない場合。ビューが既にロードされている場合は、正常に機能します。おかしい、えっ?

だから、私の場合に起こったことはこれです:

  1. 通常の起動プロセスでは、NSFetchedResultsControllerを作成する必要があります。
  2. 何千ものオブジェクトがフェッチされるため、フレッシュフェッチにはかなりの時間がかかります。これを軽減するために、フェッチはa)キャッシュを使用し、b)バックグラウンドで行われるため、他のアクティビティを続行できます
  3. 通常、UIは応答性が高く、ユーザーは何かを実行できますが、ユーザーが新しいオブジェクトを作成したいという要望を表明するずっと前に、フェッチは完了します。
  4. ただし、アプリがバックグラウンドで起動される場合があります(たとえば、WatchKitイベントやバックグラウンドフェッチなどから)。起動の一部で、データストアに新しいオブジェクトをすぐに作成する必要があります。
  5. フェッチが完了する前に新しいオブジェクトが作成された場合、アプリがクラッシュしました。

解決策は、オブジェクトを作成する前にフェッチが完了していることを確認することです(フェッチに影響します)。

あるいは、キャッシュを削除することもできますが、実際にはパフォーマンスが低下します。

デバッガからの警告に注意してください

キャッシュを無効にしたり、+ deleteCacheWithNameを使用したりせずに、NSFetchedResultsControllerのフェッチリクエスト、その述語、またはそのソート記述子を不正に変更しました:

変更されたのはリクエスト、述語、またはソート記述子ではなく、フェッチが行われている間に結果セットを変異させたとより正確に説明できるため、この状況をまったくキャプチャしません進捗

この小さな雑学を追跡するのに私は永遠にかかりました。あなたが恩恵を受けることを願っています。

1
SG1

同じように実装するクラスの数-(NSFetchedResultsController *)resultsメソッド、それぞれに異なるキャッシュを使用しますか?私は同じ問題を抱えていましたが、異なるNSPredicateを持っているため、いくつかのクラスの前に別のキャッシュ名を使用することでそれを修正すると思います。

1
jigzat