iOS: les cellules CellForRowAtIndexPath se mélangent

Je vais commencer par dire que j'ai vu ces questions:

iOS: UITableView mélange datatables lorsque vous faites défiler trop vite

(personnalisé) Mélange de UITableViewCell après le défilement

Objets mélangés après défilement dans UITableView

Le premier et le dernier semblaient très pertinents à mon problème, mais je suis assez certain que j'ai la logique pour chaque section de déterminer ce qui devrait apparaître dans la cellule (datatables), et pourtant ils se mélangent encore.

Ce qui suit est le code pertinent:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //Note: the if (cell == nil) thing is no longer required in iOS 6 static NSSsortingng *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } if (closestRenter != nil) { NSLog(@"CLOSEST RENTER!"); [self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; } else { NSLog(@"NO CLOSEST RENTER"); [self setupCellsWithNoClosestRenterCell:cell atIndexPath:indexPath]; } if (indexPath.section == 0) { for (UIView *view in cell.contentView.subviews) { NSLog(@"WHAT THE HECK"); [view removeFromSuperview]; } } return cell; 

}

Informations pertinentes ici:

1) ClosestRenter n'est PAS nul … il existe. Donc la clause else ne devrait jamais être exécutée … et c'est le cas.

2) Dans le code:

 [self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; 

Il y a un simple:

 if (indexPath.section == 0) { cell.textLabel.text = @"PLACE HOLDER"; } else { // Populate the cell with data. (creates a view (with controller etc) and loads it into the cell) } 

3) Il y a 2 sections en tout time.

Le problème est que la section 0 (la première section) ne devrait avoir rien de plus que cette string d'espace réservé. Section 1 devrait contenir mes sous-vues personnalisées (dans les cellules, ce qu'il fait).

La section 0 contient initialement la string de caractères generics, mais une fois que je défile (et la section n'est plus visible) et que je la remonte (rapidement), il y a parfois une cellule apparemment random de la section 1 … que diable? Comment? Je suis réticent à blâmer la réutilisation des cellules, mais à ce stade, en dehors de quelque chose de vraiment stupide, je ne sais pas ce que c'est.

La partie dérangeante ici est que la cellule de la section 0 (il n'y a qu'une seule ligne) n'a pas de sous-vues. Mais quand je fais défiler rapidement vers le haut et vers le bas il en obtient un (de la section 1 apparemment) et puis je reçois les messages du journal "WHAT THE HECK" …

Il convient de mentionner que la boucle for (celle avec les messages de diable) résout le problème (car elle supprime les sous-vues indésirables), mais il doit y avoir une meilleure façon. Il se sent mal en ce moment.

Des idées?

(Sentez-vous libre de marquer cela comme un doublon, mais je suis à peu près certain qu'il se passe quelque chose d'autre ici).

Merci.

Donc, après un peu de frustration et une parsing minutieuse, j'ai découvert pourquoi les cellules se mélangeaient.

Mon hypothèse sur la réutilisation des cellules (en particulier avec les identifiants) était le problème.

Auparavant, je faisais ceci:

 static NSSsortingng *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } 

Ce qui est génial et tout, mais il y a un problème critique. Toutes les cellules étaient techniquement les mêmes en dessous … après qu'elles soient toutes allouées (pas nulles), le système ne pouvait pas déterminer quelle cellule réutiliser, quelle que soit la section.

Cela signifiait que n'importe quelle cellule pouvait être attrapée de la file, avec tout ce qu'elle contenait, et bloquée n'importe où (malgré mes vérifications pour s'assurer que la section 1 allait bien dans la section 1 et que la section 0 restait là) .

La solution:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //Note: the if (cell == nil) thing is no longer required in iOS 6 static NSSsortingng *CellIdentifier1 = @"Cell"; static NSSsortingng *CellIdentifier2 = @"Cell2"; UITableViewCell *cell; if (indexPath.section == 0) { if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier1]; } else { cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1]; } } else { if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier1]; } else { cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2]; } } if (closestRenter != nil) { NSLog(@"CLOSEST RENTER!"); [self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; } else { NSLog(@"NO CLOSEST RENTER"); [self setupCellsWithNoClosestRenterCell:cell atIndexPath:indexPath]; } return cell; 

}

Comme vous pouvez le voir, la section 0 aura son propre identifiant de cellule. Comme le fera la section 1. Le résultat est que lorsqu'une cellule doit être supprimée, elle vérifie dans quelle section se trouve l'indexPath et récupère la cellule correcte.

Ugh, un tel problème frustrant mais maintenant tout est logique 🙂

Ajouter un autre a résolu mon problème. Où j'ai réinitialisé les modifications apscopes à la cellule.

 if (! self.cell) { self.cell = [[LanguageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; self.cell.accessoryType = UITableViewCellAccessoryNone; } else { self.cell.checkImage.image = NO; } 

Il y a plusieurs façons de traiter ce problème de réutilisation de cellules (et c'est ce que le problème est), et la façon dont vous le faites maintenant est ok. Le problème est que lorsque vous faites défiler vers le bas et sauvegarder à nouveau, la cellule qui est returnnée pour la section 0 pourrait être une cellule qui était précédemment utilisée pour la section 1, donc il y aura des sous-vues que vous mettez là.

Une autre façon de gérer cela est de créer deux cellules prototypes différentes dans le storyboard, et de returnner l'une avec une simple label pour la section 0, et de returnner l'autre, avec toutes les sous-vues ajoutées dans IB, pour la section 1. De cette façon, obtiendra toujours le bon type de cellule pour chaque section sans avoir à supprimer les sous-vues – il vous suffit de remplir à nouveau la cellule avec datatables correctes.