开发者

ExecuteFetchRequest intermittently throwing exception with same parameters. "not key value coding-compliant for the key"

EDIT Thanks to Matt's post I now understand that I should not be trying to access 'started' as an array. However, if that is the case, I would like to know why this code appears to be working in other places. It still seems to me that this should be "one-or-the-other." It should work or it shouldn't.

ORIGINAL I'm using the same fetch request in various parts of my code to find the most recent game:

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

'Game' is an NSManagedObject and 'started' is a date attribute. 'started' is set exactly once per object in awakeFromInsert. It is nev开发者_运维技巧er changed after that. Game is never directly instantiated, but it has three subclasses. I have tried making Game both abstract and concrete, but neither has any effect on this problem.

I'm using an NSManagedObjectContext category to perform the fetch, as shown on cocoa with love here http://cocoawithlove.com/2008/03/core-data-one-line-fetch.html.

The error I am getting is the following:

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";
}

It looks to me like the predicate might be trying to apply @max to a single NSDate, instead of all 'started' attributes in all games. I'm not sure though. I'm not very good with predicates, and it took me a lot of trial and error to make this one. I don't understand how the exact same fetch can have errors in different places, though.

The fetch is not part of an NSFetchedResultsController, but I am using a fetchedResultsController in the class where I'm getting the error. For example:

- (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];
...
}

and also here:

- (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;
}

This exact fetch is performed several times in several places, for example on startup, but it only crashes in one class. As I said it is intermittent, but it seems to be sometime after I create a new Game object. The game is created in one tab, and the code above is from a second tab which shows history.

I have seen a similar error here. In that case the problem was solved by restarting the computer, which finally allowed XCode to realize that the attribute had been deleted from the model. I have tried that, and I'm still experiencing the problem. I have also tried deleting and recreating the 'started' attribute in the model. I have also read the Core Data Troubleshooting Guide, but was unable to find any help there either.


Predicates are applied to one source object at a time. If your source object does not have an array property, you can't use an array operator.

In your case, the predicate says:

Look at a given "Game". If its own "started" property is equal to its own "started" property with the @max KVC array operator applied, then this predicate will be true.

This is not what you want. The only situation where you'd use a KVC array operator in a predicate is where a property on an object is an array. e.g.

Fetch every "Season" where the "games.@max.homeTeamScore > 50" (i.e. seasons where a home team scored more than 50 in a game). This would work because the "games" property on a "Season" would be an array, so games.homeTeamScore would also be an array.

However, the "started" property on a single Game is not an array. The array you want to operate on is actually the array of all games, which is not a property of a game.

The only twisted way you could access the array of all games would be to fetch the array of all games first, then apply the array operator outside the predicate and then on the inside of the predicate only apply the equality test.

i.e. fetch all games first, then refetch with:

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

But this is not the smart thing to do either.

Ultimately, the correct way to fetch the game with the latest starting date as you're trying to do, can't be done with the single line fetch method.

You'll need to create a variant of the method that allows you to setSortDescriptors: on the fetch request (to sort by "started", descending) and then setFetchLimit:1 on the fetch request to only get first result.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜