2009-11-21 6 views
2

J'ai un contrôleur de résultats récupéré avec un prédicat sur mon entité Thing qui ressemble à ceci: "thingDomain.domainCurrentAccount! = NULL". Il trouve tous mes objets Thing qui sont dans le domaine actuel. Le domaine actuel est défini par une relation un-à-un entre l'entité de compte et l'une des entités de domaine. Chaque chose appartient à un domaine, et chaque domaine a beaucoup de choses. Tous les domaines sauf un ont une relation NULL avec le compte.Est-ce que re-fetch NSFetchedResultsController fait quelque chose?

Cela fonctionne et ma tableview est heureux.

Plus tard, je modifie le domaine actuel en modifiant la relation avec le compte. J'ajoute plus de choses à un domaine qui est maintenant le domaine en cours, elles sont ajoutées à la table puisqu'elles satisfont le prédicat. Cependant, les objets qui appartiennent au domaine maintenant non existant restent dans la table même s'ils ne satisfont plus le prédicat.

J'ai essayé de récupérer, mais cela n'a eu aucun effet, alors je suis perplexe quant à savoir ce que l'extraction fait de nouveau. Réévalue-t-il le prédicat par rapport aux entités?

J'ai résolu le problème en supprimant toutes les choses dans le domaine actuel avant de changer le domaine actuel, mais je pense que je ne devrais pas avoir à le faire.

Répondre

4

Avez-vous rechargé la vue de table après avoir effectué la récupération à nouveau?

Cela a fonctionné pour moi:

self.fetchedResultsController = nil; 
NSError *error = nil; 
if (![self.fetchedResultsController performFetch:&error]) { 
    NSLog(@"Error in refetch: %@",[error localizedDescription]); 
    abort(); 
} 

[self.tableView reloadData]; 

MISE À JOUR
Le contrôleur tiré par les cheveux de résultats est observer les choses objets pour les changements, pas des objets de domaine. Puisque nous modifions l'objet Compte sur un domaine, il est logique que le contrôleur de résultats récupérés ne soit pas mis à jour (à l'exception de la nouvelle chose).
La solution idéale serait un moyen de dire au contexte d'objet géré ou au contrôleur de résultats récupérés que les choses exactes ont "changé" (boucle sur les choses du domaine qui avaient précédemment le compte), mais ce serait toujours un processus manuel.
L'alternative est d'effectuer de nouveau chercher et de recharger la table qui a fonctionné pour moi.

J'ai créé ce modèle en fonction de votre description:

compte < ---> Domaine < --- >> Chose

Pour tester cela, j'ai créé choses "One" et "Deux" en Domaine domainOne et Things "Three", "Four" et "Five" dans Domain domainTwo. domainOne a le compte alors que domainTwo n'a pas de compte.
Lorsque l'application est chargée, la vue de table affiche les éléments "One" et "Two" comme prévu.
Quand je tape "Change", domainTwo se voit attribuer le compte et domainOne perd son compte. En outre, une nouvelle chose nommée "Six" est créée dans domainTwo.
Chose "Six" apparaît avec "Un" et "Deux" même s'ils ne répondent plus au prédicat. Cela correspond au problème que vous décrivez.
Puis, je tape "Refetch" et la table se recharge avec "Three", "Four", "Five" et "Six". C'est le comportement désiré.

Voici le code du contrôleur de vue pertinent:

- (void)addTestData { 
    account = [NSEntityDescription insertNewObjectForEntityForName:@"Account" inManagedObjectContext:self.managedObjectContext]; 
    domainOne = [NSEntityDescription insertNewObjectForEntityForName:@"Domain" inManagedObjectContext:self.managedObjectContext]; 
    domainTwo = [NSEntityDescription insertNewObjectForEntityForName:@"Domain" inManagedObjectContext:self.managedObjectContext]; 
    [domainOne setValue:account forKey:@"domainCurrentAccount"]; 

    NSArray *thingNames = [NSArray arrayWithObjects:@"One", @"Two", @"Three", @"Four", @"Five", nil]; 
    for (NSString *name in thingNames) { 
     NSManagedObject *thing = [NSEntityDescription insertNewObjectForEntityForName:@"Thing" inManagedObjectContext:self.managedObjectContext]; 
     [thing setValue:name forKey:@"thingName"]; 
     if (name == @"One" || name == @"Two") { 
      [thing setValue:domainOne forKey:@"thingDomain"]; 
     } else { 
      [thing setValue:domainTwo forKey:@"thingDomain"]; 
     } 
    } 
} 

- (void)change { 
    [domainTwo setValue:account forKey:@"domainCurrentAccount"]; 
    [domainOne setValue:nil forKey:@"domainCurrentAccount"]; 
    NSManagedObject *thing = [NSEntityDescription insertNewObjectForEntityForName:@"Thing" inManagedObjectContext:self.managedObjectContext]; 
    [thing setValue:@"Six" forKey:@"thingName"]; 
    [thing setValue:domainTwo forKey:@"thingDomain"]; 
} 

- (void)refetch { 
    self.fetchedResultsController = nil; 
    NSError *error = nil; 
    if (![self.fetchedResultsController performFetch:&error]) { 
     NSLog(@"Error in refetch: %@",[error localizedDescription]); 
     abort(); 
    } 

    [self.tableView reloadData]; 
} 
- (void)viewDidLoad { 
    [super viewDidLoad]; 

    UIBarButtonItem *changeButton = [[UIBarButtonItem alloc] initWithTitle:@"Change" style:UIBarButtonItemStyleBordered target:self action:@selector(change)]; 
    self.navigationItem.leftBarButtonItem = changeButton; 
    [changeButton release]; 

    UIBarButtonItem *refetchButton = [[UIBarButtonItem alloc] initWithTitle:@"Refetch" style:UIBarButtonItemStyleBordered target:self action:@selector(refetch)]; 
    self.navigationItem.rightBarButtonItem = refetchButton; 
    [refetchButton release]; 

    [self addTestData]; 

    NSError *error = nil; 
    if (![[self fetchedResultsController] performFetch:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 
} 
+0

J'ai essayé sans effet.Cela ne devrait pas être nécessaire, car le contrôleur de résultats récupéré surveille tous les changements sur le MOC et effectue toutes les autres mises à jour de table dont il a besoin sur sa collection. Recharger les vues de table est un dernier recours car il n'est pas animé et tue toute animation en cours. –

+0

J'ai expliqué pourquoi cela ne fonctionnait pas comme prévu et ajouté des détails pour ma solution originale qui fonctionne. – gerry3

+0

Intéressant, mais il y a une différence clé dans votre code: dans le mode de récupération, vous jetez le contrôleur de résultat récupéré en cours et en créez un nouveau. Je demande spécifiquement d'utiliser le même contrôleur et de lui demander de faire un autre chargement, ce que j'avais supposé, en le faisant réévaluer toutes les entités par rapport au prédicat. Il est possible que cela ne fasse rien, mais les docs ne le disent pas. Récupérer peut être un événement ponctuel et une fois qu'il a des résultats, plus besoin d'aller chercher. Il n'y a pas de "dénouer" pour jeter les résultats qu'il a. –

Questions connexes