ExecuteFetchRequest 间歇性地抛出具有相同参数的异常。 “密钥不符合密钥值编码”

发布于 2024-10-01 02:34:44 字数 2594 浏览 1 评论 0 原文

编辑感谢马特的帖子,我现在明白我不应该尝试将“started”作为数组访问。但是,如果是这样的话,我想知道为什么这段代码似乎在其他地方工作。在我看来,这应该是“一个或另一个”。它应该起作用,或者不应该起作用。

原创 我在代码的各个部分使用相同的获取请求来查找最近的游戏:

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

“Game”是一个 NSManagedObject,“started”是一个日期属性。 'started' 在 awakeFromInsert 中为每个对象设置一次。此后就再也没有改变过。游戏永远不会直接实例化,但它具有三个子类。我尝试过让 Game 变得抽象和具体,但都对这个问题没有任何影响。

我正在使用 NSManagedObjectContext 类别来执行获取,如 cocoa with love 所示 http://cocoawithlove.com/2008/03/core-data-one-line-fetch.html

我收到的错误如下:

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

这种精确的获取在多个地方执行多次,例如在启动时,但它只在一个类中崩溃。正如我所说,它是间歇性的,但似乎是在我创建新的游戏对象之后的某个时间。游戏是在一个选项卡中创建的,上面的代码来自显示历史记录的第二个选项卡。

我看到了类似的错误

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 never 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

软的没边 2024-10-08 02:34:44

谓词一次应用于一个源对象。如果源对象没有数组属性,则无法使用数组运算符。

在你的例子中,谓词说:

查看给定的“游戏”。如果是自己的
“started”属性等于它自己的属性
使用 @max KVC 的“started”属性
应用数组运算符,然后这个
谓词将为真。

这不是你想要的。在谓词中使用 KVC 数组运算符的唯一情况是对象上的属性数组。例如,

获取“[email protected] > 50 的每个“季节” ”(即主队单场得分超过 50 分的赛季)。这是可行的,因为“Season”上的“games”属性将是一个数组,因此 games.homeTeamScore 也将是一个数组。

但是,单个游戏的“started”属性不是数组。你要操作的数组实际上是所有游戏的数组,它不是游戏的属性。

访问所有游戏的数组的唯一扭曲方法是首先获取所有游戏的数组,然后在谓词外部应用数组运算符,然后在谓词内部仅应用相等测试。

即首先获取所有游戏,然后重新获取:

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

但这也不是明智的做法。

最终,正如您所尝试的那样,无法使用单行获取方法来获取具有最新开始日期的游戏的正确方法。

您需要创建该方法的变体,允许您在获取请求上设置 setSortDescriptors: (按“开始”降序排序),然后在获取请求上设置 setFetchLimit:1 以仅获取第一个结果。

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 "[email protected] > 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文