2

編集マットの投稿のおかげで、配列として「開始」にアクセスしようとしてはならないことがわかりました。ただし、その場合、このコードが他の場所で機能しているように見える理由を知りたいです。これはまだ「どちらか一方」であるべきだと私には思えます。うまくいくか、うまくいかないか。

オリジナル コードのさまざまな部分で同じフェッチ要求を使用して、最新のゲームを見つけています。

Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:@"Game" withPredicate:@"started == started.@max"] anyObject];

「Game」は NSManagedObject で、「started」は日付属性です。「開始」は、awakeFromInsert のオブジェクトごとに 1 回だけ設定されます。それ以降は一度も変更されていません。ゲームが直接インスタンス化されることはありませんが、3 つのサブクラスがあります。ゲームを抽象的かつ具体的にしようとしましたが、どちらもこの問題には影響しません。

ここhttp://cocoawithlove.com/2008/03/core-data-one-line-fetch.htmlで cocoa with love に示されているように、フェッチを実行するために NSManagedObjectContext カテゴリを使用しています。

私が得ているエラーは次のとおりです。

Serious application error.  An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.  [<__NSDate 0xebb1130> valueForUndefinedKey:]: this class is not key value coding-compliant for the key @max. with userInfo {
    NSTargetObjectUserInfoKey = "2010-11-06 11:16:53 GMT";
    NSUnknownUserInfoKey = "@max";
}

すべてのゲームのすべての「開始」属性ではなく、述語が @max を単一の NSDate に適用しようとしているように見えます。よくわかりませんが。私は述語が苦手で、これを作成するのに多くの試行錯誤が必要でした。ただし、まったく同じフェッチで別の場所でエラーが発生する可能性があることはわかりません。

フェッチは NSFetchedResultsController の一部ではありませんが、エラーが発生しているクラスで fetchedResultsController を使用しています。例えば:

- (void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath{
Game *game = [self.frc objectAtIndexPath:indexPath];
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:@"Game" withPredicate:@"started == started.@max"] anyObject]; // Sometimes we get past this line, sometimes we don't...

NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:@"EEE, MMM d, yyyy h:mm a"];

if (game != lastGame)
    cell.detailTextLabel.text = [format stringFromDate:game.started];
else
    cell.detailTextLabel.text = @"In Progress";
[format release];
...
}

そしてここにも:

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
    Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:@"Game" withPredicate:@"started == started.@max"] anyObject];
    if (lastGame == [frc objectAtIndexPath:indexPath])
        return NO;
    return YES;
}

この正確なフェッチは、起動時など、いくつかの場所で数回実行されますが、クラッシュするのは 1 つのクラスだけです。私が言ったように、それは断続的ですが、新しい Game オブジェクトを作成した後のいつかのようです。ゲームは 1 つのタブで作成され、上記のコードは履歴を表示する 2 番目のタブからのものです。

ここで同様のエラーが発生しました。その場合、問題はコンピューターを再起動することで解決され、最終的に XCode は属性がモデルから削除されたことを認識することができました。私はそれを試しましたが、まだ問題が発生しています。また、モデルの「開始」属性を削除して再作成しようとしました。Core Data トラブルシューティング ガイドも読みましたが、ヘルプも見つかりませんでした。

4

1 に答える 1

1

述語は、一度に 1 つのソース オブジェクトに適用されます。ソース オブジェクトに配列プロパティがない場合、配列演算子は使用できません。

あなたの場合、述語は次のように述べています。

与えられた「ゲーム」を見てください。@max KVC 配列演算子が適用された独自の「開始済み」プロパティが独自の「開始済み」プロパティと等しい場合、この述語は true になります。

これはあなたが望むものではありません。述語で KVC 配列演算子を使用する唯一の状況は、オブジェクトのプロパティが配列である場合です。例えば

「games.@max.homeTeamScore > 50」のすべての「シーズン」を取得します (つまり、ホームチームが試合で 50 を超える得点を挙げたシーズン)。「シーズン」の「ゲーム」プロパティは配列になるため、これは機能するため、games.homeTeamScore も配列になります。

ただし、単一のゲームの「開始」プロパティは配列ではありません。操作対象の配列は、実際にはすべてのゲームの配列であり、ゲームのプロパティではありません。

すべてのゲームの配列にアクセスできる唯一のねじれた方法は、最初にすべてのゲームの配列をフェッチし、次に述語の外側で配列演算子を適用し、次に述語の内側で等価テストのみを適用することです。

つまり、最初にすべてのゲームを取得してから、次のように再取得します。

fetchObjectsForEntityName:@"Game" withPredicate:@"started == %@", [allGames valueForKey:@"@max.started"]

しかし、これも賢明なことではありません。

最終的に、最新の開始日でゲームをフェッチする正しい方法は、1 行のフェッチ メソッドでは実行できません。

フェッチ リクエストで setSortDescriptors: (「開始」、降順で並べ替える) を許可するメソッドのバリアントを作成し、フェッチ リクエストで FetchLimit:1 を設定して最初の結果のみを取得できるようにする必要があります。

于 2010-11-09T01:14:39.443 に答える