J'utilise un NSFetchedResultsController de manière standard pour mettre à jour un UITableView chaque fois que quelque chose change dans les entités de données de base associées. Je fais la même chose que décrit in the Apple documentation.Délégué NSFetchedResultsController allouant trop de UITableViewCells
Le problème que j'ai est quand je fais une insertion en masse de nouvelles entités de données de base. Cela provoque le délégué NSFetchedResultsController à allouer (et insérer) une nouvelle cellule pour chaque entité, mais il le fait sans recycler les UITableViewCells (par exemple, dequeueReusableCellWithIdentifier:
renvoie toujours null). Cela signifie l'allocation de potentiellement 100s de UITableViewCells, ce qui peut entraîner des problèmes de mémoire. Est-ce que quelqu'un sait d'un correctif ou d'une solution de contournement? Merci.
Edit 1:
Dans ma sous-classe UITableViewController j'ai les méthodes standard NSFetchedResultsControllerDelegate. Je crois que c'est identique à l'exemple d'Apple.
-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom];
// Reloading the section inserts a new row and ensures that titles are updated appropriately.
[tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationTop];
break;
}
}
-(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationBottom];
break;
}
}
-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}
également dans mon sous-classe UITableViewController je donne les résultats suivants pour aller chercher une cellule pour une indexPath donnée:
-(void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
Waypoint *waypoint = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [waypoint comment];
}
-(UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"WaypointCell"; // matches identifier in XIB
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog(@"new cell");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
NSLog(@"recycled cell");
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Dans la fonction tableView:cellForRowAtIndexPath:
j'ai ajouté des déclarations NSLog à afficher ce qui se passe.
Voici ce qui se passe. Le UITableViewController mentionné ci-dessus est poussé sur la pile de navigation. Une requête asynchrone s'éteint et récupère un tas de données, et crée ou modifie les données relatives à ce fetchController. Une fois que [self.tableView endUpdates]
est appelé, le système commence à créer et à insérer les UITableViewCells dans UITableView. Dans la console du débogueur, la sortie "new cell" est imprimée plusieurs fois (nombre possible dans les 100), ce qui est le cas pour chaque nouvelle entité créée. Ce n'est qu'après le chargement de la vue de table (si elle ne s'est pas bloquée à cause de problèmes de mémoire) et que je commence à faire défiler la sortie "cellule recyclée" dans la console.
Je viens de remarquer que vous avez un total de 4 questions et aucun d'entre eux ont une réponse acceptée. Si la réponse résout votre problème, vous devez accepter la réponse en cliquant sur le signe vert. :) – Florin
Vous devrez montrer votre code. Ce n'est pas un comportement normal. Le délégué ne crée pas lui-même de cellules. Vous insérez incorrectement les cellules quelque part. – TechZen
Florin: Je vais revoir et mettre à jour le cas échéant. Merci pour le heads-up. TechZen: J'ai ajouté du code à la publication originale. J'espère que cela éclaircira le problème. A l'origine, j'ai utilisé une tableview cell personnalisée avec un fichier .xib, mais j'ai simplifié le code pour utiliser un UITableViewCell standard et le comportement est exactement le même. Corrigez que le délégué ne crée pas les cellules.C'est l'appel [tableView endUpdates] du délégué qui le fait. Merci. – chris