5

NSFetchedResultsController を使用して、フェッチされた管理対象オブジェクトを 1 つのセクションを持つテーブル ビューに表示することを管理しています。テーブルは空の状態で開始され、ユーザーは UI を使用してテーブルに新しいエンティティを追加できます。現状では、プログラムは最初のエンティティを追加するときに常に機能し、2 番目のエンティティを追加すると常にクラッシュします。クラッシュ時にエラーが表示されない場合もあれば、さまざまな種類のエラーが発生する場合もあります (一部を以下に示します)。ログ ステートメントとトレースを通じて、NSFetchResultsController のデリゲートの controllerWillChangeContent ([self.tableView beginUpdates]; を呼び出す) メソッドが終了した直後に、コード内の他のメソッドが呼び出される前に、プログラムがクラッシュすることがわかります。これが私のコードの関連部分の一部です。NSFetchedResultsController の構成:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Beer"
                                    inManagedObjectContext:self.managedObjectContext]];

// Configure request's entity and predicate
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];

NSString *expression = [NSString stringWithFormat:@"brewery.name LIKE \"%@\"", self.brewery.name];
NSPredicate *predicate = [NSPredicate predicateWithFormat:expression];
[fetchRequest setPredicate:predicate];
self.resultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                             managedObjectContext:self.managedObjectContext
                                                               sectionNameKeyPath:nil
                                                                        cacheName:nil];
self.resultsController.delegate = self;
[fetchRequest release];

NSError *error = nil;
BOOL success = [resultsController performFetch:&error];
if (!success) {
    NSLog(@"Error fetching request %@", [error localizedDescription]);
}

新しいエンティティの追加:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Beer" inManagedObjectContext:self.managedObjectContext];
Beer *beer = [[Beer alloc] initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];
beer.name = beerName;
beer.brewery = self.brewery;

セクションが 1 つのテーブルを表示する際の問題に関するドキュメントの警告を確認しましたが、Apple の回避策を使用しましたが、役に立ちませんでした。とにかく、これらのメソッドはクラッシュの前に呼び出されません。

私が受け取ったエラーのいくつか:

Serious application error.  Exception was caught during Core Data change processing: *** -[NSCFString compareObject:toObject:]: unrecognized selector sent to instance 0x4e808c0 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[CALayer compareObject:toObject:]: unrecognized selector sent to instance 0x4e53b80 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[UITextTapRecognizer controllerWillChangeContent:]: unrecognized selector sent to instance 0x4ca5d70 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[CALayer controllerWillChangeContent:]: unrecognized selector sent to instance 0x4e271a0 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[NSCFNumber countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x4c96ee0 with userInfo (null)

ご覧のとおり、エラー (表示された場合) は、コードに変更が加えられていない場合でも一貫性がありません。

誰かが私が間違っていることを理解できますか?

4

5 に答える 5

4

一貫性のないエラーは、オーバーリリースの問題の可能性を示しています。特に、デリゲートを変更してデータをリロードするだけなので、問題は解決します。個人的には、問題をコーディングするのではなく、問題を解決するために時間を費やします。コードの問題が確実に発生しているため、後でどこかで発生する可能性があります。

私は次のことをします:

  1. NSZombieをオンにします
  2. のブレークポイントを追加しますobjc_exception_throw
  3. デバッガーで実行

例外が発生した場合は、メモリアドレスを調べて、何がどこでアクセスされているかを確認します。これにより、問題が切り分けられ、何が起こっているかがわかります。それでも問題が明らかにならない場合は、NSFetchedResultsControllerデリゲートメソッドを投稿して、何か奇妙なことがあるかどうかを確認できるようにすることも役立ちます。

元の質問を追加情報で更新することをお勧めします。

于 2010-03-09T14:57:31.063 に答える
1

新しいエンティティを作成するコードはすべて奇妙です。代わりにこれを使用するのはどうですか:

Beer* beer = [NSEntityDescription insertNewObjectForEntityForName: @"Beer" 
    inManagedObjectContext: self.managedObjectContext];
beer.name = @"Grolsch";

また、あなたは電話していませんNSManagedObjectContext#save:。しかし、今示したコードの一部でそれを行っているのではないでしょうか?

于 2010-02-11T03:20:58.697 に答える
1

この特定の問題は解決しませんでしたが、必要な機能を提供し、問題が発生しないクラスを作成するために、少し異なるアプローチを取りました。私はまだ NSFetchedResultsController を使用していますが、4 つのデリゲート メソッドをすべて実装するのではなく、単に [tableView reloadData] を呼び出す controllerDidChangeContent: のみを実装しています。

これは、ストレージに Core Data を使用する新しいナビゲーション ベースのアプリケーションを XCode で作成する場合に RootViewController クラスに含まれる実装です。テーブル編集のアニメーションをある程度制御できなくなる可能性がありますが、はるかに単純で、私の目的には問題なく機能します。

于 2010-02-11T21:12:56.750 に答える
1

最近、同様のバグがありました-あなたの問題は、特にリリースしすぎていることです:

[sortDescriptors release];

sortDescriptors オブジェクトを取得します

[NSArray arrayWithObjects:sortDescriptor, nil];

「alloc」、「copy」、または「new」がないため、自動解放されたオブジェクトを返します。早期にリリースするため、NSFetchRequest がそれを使用するときと、プールによって解放されるときの 2 つの場所でクラッシュする可能性があります。詳細については、Apple のメモリ管理ガイドを参照してください。

于 2011-01-20T14:34:22.870 に答える
0

これは古いものですが、他の人が同じ問題を抱えているため、何が起こっているのかを理解しようと何時間も費やし、最終的にこれらのランダムなクラッシュを引き起こしているソート記述子の問題を発見しました.

エラー メッセージはさまざまですが、以下のように、ほとんどが compareObject:toObject セレクターに関連していました。

-[_ NSCFSet compareObject:toObject:]: 認識されないセレクターがインスタンスに送信されました -[ _NSCFString compareObject:toObject:] 認識されないセレクターがインスタンスに送信されました

私の提案は、すべてのソート記述子と述語をコードから削除してから、それらを 1 つずつ追加して問題の場所を見つけることです。

幸運を!ログ

于 2010-10-17T09:09:39.217 に答える