Lorsque Apple a développé le UITableView
pour le premier iPhone, ils ont eu un problème de performances lors du défilement. Ensuite, un ingénieux ingénieur a découvert que la cause en était que l'allocation des objets venait avec un prix, alors il a trouvé un moyen de réutiliser les cellules.
"L'allocation d'objet a un coût de performance, en particulier si l'allocation doit se produire à plusieurs reprises sur une courte période, par exemple lorsque l'utilisateur fait défiler une vue de table. Si vous réutilisez des cellules au lieu d'en allouer de nouvelles, vous améliorez considérablement les performances de vue de table."
Source: Bibliothèque de référence iOS
Pour réutiliser une cellule que vous utilisez:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Maintenant, ce que je me demande, c'est ce qui se passe réellement ici? A-t-il l'air dans le TableView s'il y a une cellule avec cet identifiant et renvoie juste celui-là? Eh bien oui duh, mais s'il envoie une référence au lieu d'allouer et j'ai une vue de table avec disons 4 cellules avec le même identifiant toutes visibles. Comment peut-il se multiplier en quatre instances sans attribuer?
Je veux le savoir car je construis un composant de type calendrier et toutes les cellules ont la même structure que le texte dans les changements. Donc, si je pouvais en quelque sorte réutiliser mes cellules au lieu de les allouer, je pense que je pourrais obtenir de meilleures performances.
Ma propre théorie est qu'elle alloue les quatre cellules (simplement parce qu'elle l'a aussi). Lorsqu'une cellule disparaît de l'écran, elle est placée dans la file d'attente de réutilisation de TableView. Lorsqu'une nouvelle cellule est nécessaire, elle recherche dans le que si une cellule avec le même identifiant est disponible, elle invoque la méthode prepareForReuse
sur cette cellule et elle se supprime de la file d'attente.
dequeueReusableCellWithIdentifier:
ne renvoie un cell
que s'il a été marqué comme prêt à être réutilisé. C'est pourquoi dans presque tous les cellForRowAtIndexPath:
méthode, vous verrez quelque chose comme
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nil == cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Do something to cell
return cell;
En effet, suffisamment de lignes seront allouées pour remplir la partie visible du tableview
(plus un ou deux de plus). Comme cells scroll
hors écran, ils sont supprimés du table
et marqués comme prêts pour reuse
. À mesure que la file d'attente des "cellules disponibles" s'allonge, votre ligne qui demande un dequeued cell
commencera à obtenir un cell
à utiliser, auquel cas vous n'aurez plus à allouer.
Le code pour deqeueueReusableCellsWithIdentifier:
ressemblera à ceci:
(Tiré d'un de mes propres projets où je fais quelque chose de similaire avec des vues/pages dans une vue de défilement paginée)
- (UIView*) dequeueReusablePage
{
UIView* page = [reusablePages_ anyObject];
if (page != nil) {
[[page retain] autorelease];
[reusablePages_ removeObject: page];
}
return page;
}
Il conserve donc un simple NSMutableSet
avec des objets réutilisables.
Lorsque les cellules défilent hors de l'écran et ne sont plus visibles, elles sont placées dans cet ensemble.
Vous commencez donc avec un ensemble vide et l'ensemble ne s'agrandira que si vous avez réellement plus de données à afficher, puis visible à l'écran.
La cellule utilisée défile en haut de l'écran, est placée dans l'ensemble, puis prise pour la cellule qui apparaît en bas de l'écran.
Le but de dequeueReusableCellWithIdentifier
est d'utiliser moins de mémoire. si nous utilisons 100 cellules dans une tableView, nous devons créer 100 cellules à chaque fois, ce qui réduit les fonctionnalités de l'application et peut provoquer un blocage. Pour cela dequeueReusableCellWithIdentifier
initialisez le nombre particulier de cellules que nous avons créées et les cellules utiliseront à nouveau pour un traitement ultérieur.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *TableIdentifier = @"YourCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TableIdentifier];
}
ExternalClassTableViewCell *myCell = [[ExternalClassTableViewCell alloc]init];
myCell.MyCellText.text = [tableData objectAtIndex:indexPath.row];
myCell.MyCellImage.backgroundColor = [UIColor blueColor];
return cell;
}