2010-11-06 36 views
2

EDIT Merci à la publication de Matt, je comprends maintenant que je ne devrais pas essayer d'accéder à «commencé» comme un tableau. Cependant, si c'est le cas, j'aimerais savoir pourquoi ce code semble fonctionner ailleurs. Il me semble encore que cela devrait être "l'un ou l'autre". Ça devrait marcher ou ça ne devrait pas marcher.ExecuteFetchRequest lançant une exception par intermittence avec les mêmes paramètres. "pas la valeur clé codage-conforme pour la clé"

ORIGINAL J'utilise la même demande de récupération dans différentes parties de mon code pour trouver le plus récent jeu:

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

« Game » est un NSManagedObject et « commencé » est un attribut de date . 'started' est défini exactement une fois par objet dans awakeFromInsert. Il n'est jamais changé après cela. Le jeu n'est jamais directement instancié, mais il a trois sous-classes. J'ai essayé de rendre le jeu à la fois abstrait et concret, mais aucun n'a d'effet sur ce problème.

J'utilise une catégorie NSManagedObjectContext pour effectuer l'extraction, comme indiqué sur le cacao avec amour ici http://cocoawithlove.com/2008/03/core-data-one-line-fetch.html.

L'erreur que je reçois est la suivante:

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

Il me semble que le prédicat peut essayer d'appliquer @max à un seul NSDate, au lieu de tous les « commencé » des attributs dans tous les jeux. Je ne suis pas sûr cependant. Je ne suis pas très bon avec les prédicats, et il m'a fallu beaucoup d'essais et d'erreurs pour faire celui-ci. Je ne comprends pas comment exactement le même fetch peut avoir des erreurs dans différents endroits, cependant.

La récupération ne fait pas partie d'un NSFetchedResultsController, mais j'utilise un fetchedResultsController dans la classe où j'obtiens l'erreur. Par exemple:

- (void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath{ 
Game *game = [self.frc objectAtIndexPath:indexPath]; 
Game *lastGame = [[[CoreDataAccess managedObjectContext] fetchObjectsForEntityName:@"Game" withPredicate:@"started == [email protected]"] 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]; 
... 
} 

et aussi ici:

- (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 == [email protected]"] anyObject]; 
    if (lastGame == [frc objectAtIndexPath:indexPath]) 
     return NO; 
    return YES; 
} 

Cette fetch exacte est effectuée à plusieurs reprises dans plusieurs endroits, par exemple au démarrage, mais il se bloque dans une seule classe. Comme je l'ai dit, il est intermittent, mais il semble que ce soit un jour après que je crée un nouvel objet Game. Le jeu est créé dans un onglet, et le code ci-dessus provient d'un deuxième onglet qui montre l'histoire.

J'ai vu une erreur similaire here. Dans ce cas, le problème a été résolu en redémarrant l'ordinateur, ce qui a finalement permis à XCode de réaliser que l'attribut avait été supprimé du modèle. J'ai essayé cela, et je suis toujours confronté au problème. J'ai également essayé de supprimer et de recréer l'attribut 'started' dans le modèle. J'ai également lu le Guide de dépannage des données de base, mais je n'ai pas trouvé d'aide non plus.

Répondre

1

Les prédicats sont appliqués à un objet source à la fois. Si votre objet source n'a pas de propriété de tableau, vous ne pouvez pas utiliser un opérateur de tableau.

Dans votre cas, le prédicat dit:

Regardez un donné "Game". Si sa propre propriété "démarrée" est égale à sa propre propriété "démarrée" avec l'opérateur de tableau @max KVC appliqué, alors ce prédicat sera vrai.

Ce n'est pas ce que vous voulez. La seule situation où vous utiliseriez un opérateur de tableau KVC dans un prédicat est où une propriété sur un objet est un tableau. par exemple.

Récupère chaque "Saison" où les "jeux. @ Max.homeTeamScore> 50" (c'est-à-dire les saisons où une équipe locale a marqué plus de 50 dans une partie). Cela fonctionnerait car la propriété "games" sur un "Season" serait un tableau, donc games.homeTeamScore serait également un tableau. Cependant, la propriété "started" sur un seul jeu n'est pas un tableau. Le tableau sur lequel vous voulez opérer est en réalité le tableau de tous les jeux, ce qui n'est pas la propriété d'un jeu. La seule façon d'accéder au tableau de tous les jeux serait d'aller d'abord chercher le tableau de tous les jeux, puis d'appliquer l'opérateur de tableau en dehors du prédicat et ensuite à l'intérieur du prédicat d'appliquer le test d'égalité.

dire tous les jeux d'abord d'extraction, REFETCH puis avec:

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

Mais ce n'est pas la meilleure chose à faire non plus.

En fin de compte, la méthode correcte pour extraire le jeu avec la dernière date de début que vous essayez de faire ne peut pas être effectuée avec la méthode de récupération de ligne unique.

Vous devrez créer une variante de la méthode qui vous permet de définir SetSortDescriptors: sur la requête d'extraction (pour trier par "démarré", descendant) puis setFetchLimit: 1 sur la requête d'extraction pour obtenir uniquement le premier résultat.

+0

Matt, Merci pour votre réponse, et aussi pour votre super site! C'est très utile pour moi de comprendre comment les prédicats devraient fonctionner. En outre, je comprends parfaitement que je pourrais récupérer tous les jeux en tant que tableau trié et prendre la première valeur. (Bien que je ne me sois pas rendu compte que je pouvais limiter mon fetch à un résultat!) Je suppose que la racine de ma question était, cependant, pourquoi mon fetch fonctionne-t-il parfois? J'utilise le même code dans applicationDidFinishLaunching et j'utilise isKindOfClass pour charger la vue appropriée, et cela fonctionne, même si, si je vous ai bien compris, cela ne devrait pas être le cas. Une idée pourquoi? – arsenius