Quelle est la méthode / norme acceptée pour charger des données de manière asynchronous dans des cellules de vue de table?

De nombreuses applications telles que Tweetbot , Twitterrific , Alien Blue , etc. qui affichent des images à partir d'une API semblent les charger de manière asynchronous. Il semble que les images visibles initiales sont chargées de manière synchrone – c'est-à-dire que les cellules visibles ne sont pas affichées tant que leurs images ne sont pas prêtes – mais que les images de ces nouvelles cellules sont chargées indépendamment des charge synchrone initiale.

Par exemple, lorsque l'user charge des tweets dans une application Twitter, les six ou sept premiers tweets qui sont visibles ne sont pas affichés tant que les images des avatars des users ne sont pas chargées, mais pour les tweets de plus de 40 t visible jusqu'à ce que l'user défile), il n'est pas nécessaire d'attendre que ces images soient chargées pour afficher les cellules initiales, car elles ne sont même pas encore visibles. Il semble que la plupart des applications permettent de charger ces images indépendamment, ce qui permet aux tweets initiaux de s'afficher plus rapidement.

Je suis confus comment faire cela, par exemple s'il y a un moyen standard que la plupart des développeurs utilisent pour faire ceci que je ne connais pas.

J'ai l'habitude d'utiliser des données de base en fournissant des objects aux données de base de la réponse, puis NSFetchedResultsController affiche dans la vue de table. Cependant, cela a l'effet négatif de nécessiter que tout soit entièrement chargé et stocké dans les objects avant que les cellules puissent être affichées. Cela signifie que si l'API me renvoie un lien d'image et que je veux afficher cette image dans la cellule, je dois charger le lien dans un UIImage et l'append aux données de base.

Donc ma question se résume essentiellement à ce que font les applications populaires telles que Tweetbot, Twitterrific, Alien Blue, etc. pour gérer les vues de table avec beaucoup d'images et de données à charger, tout en permettant un chargement très rapide, sans avoir à charger des données inutiles, tout en conservant des performances de défilement élevées?

Il y a beaucoup de solutions à cela et vous pouvez en find beaucoup ici sur débordement de stack.

L'idée de base est que vous voulez charger l'image soit dans un bloc ou une NSOperation . Je préfère un NSOperation parce que vous pouvez les annuler ce qui est utile quand une cellule défile hors de l'écran.

Je recommand un controller pour gérer votre queue d'images. Votre cellule de table request l'image du controller et si le controller a l'image, elle la renvoie immédiatement. Si ce n'est pas le cas, il returnne zéro et récupère l'image.

De là, il y a des options. Vous pouvez utiliser un bloc pour callbacker lorsque l'image est récupérée. Je ne suis pas fan de ça mais c'est assez populaire. Je préfère utiliser une NSNotification lorsque l'image est reçue et que la cellule écoute la NSNotification à remplir.

J'ai un échantillon assez compliqué sur github qui gère cela aussi bien que beaucoup plus. Il se trouve dans mon référentiel partagé sur http://github.com/ZarraStudios/ZDS_Shared . La class principale s'appelle ZSAssetManager .

Remarque: Cet exemple de code date de quelques années. Il n'est donc pas prêt pour ARC et nécessitera quelques modifications. C'est probablement aussi plus compliqué que ce que vous searchz car il gère également la détection de la bande passante et la réaction. Cependant, il vous montre ce que fait une application de production / haute qualité pour gérer le chargement asynchronous d'images.

Prendre plaisir.

La documentation Apple présente un exemple de code montrant comment charger des images paresseusement dans des cellules de vue de table. Il prend soin d'annuler les téléchargements pour les images qui défilent à l'abri des regards et de ne pas démarrer les téléchargements d'images jusqu'à ce que l'user cesse de défiler.

Il n'y a pas de réponse parfaite. C'est une forme d'art pour améliorer et peaufiner les différentes pièces impliquées pour fournir la meilleure expérience user pour votre application. Résumée cependant, ce que vous avez décrit implique une combinaison compétente de ce qui suit:

Chargement paresseux

Pour le chargement paresseux mon goto préféré absolu est SDWebImage . Pour réaliser l'effet que vous décrivez où les 6 ou 7 premiers tweets ne se chargent pas jusqu'à ce que les images soient là, vous pouvez masquer les tweets initialement et utiliser les blocs d'achèvement de SDWebImage pour les afficher.

Pagination

La pagination fait reference à la pratique consistant à récupérer un nombre défini d'objects au départ et à faire descendre le nombre X d'objects suivant de manière asynchronous avant que l'user ne les atteigne (habituellement initié par un défilement). Vous pouvez également étendre cette fonction pour ne charger les images que lorsque le défilement de l'user ralentit ou s'arrête, afin de ne pas perdre de time à charger les images défilées par l'user. Il y a de très bons exemples sur GitHub, comme NMPaginator , ou vous pouvez rouler les vôtres en utilisant les methods UIScrollViewDelegate .

Configurez votre délégué scrollview et implémentez:

 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (!decelerate) { [self loadImagesForVisibleRows]; } } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [self loadImagesForVisibleRows]; } 

Ajoutez ensuite une méthode loadImagesForVisibleRows où vous utilisez [self.tableView indexPathsForVisibleRows]; pour accéder aux lignes visibles et paresseux charger les images pour ces lignes.

Charges utiles efficaces

Enfin, si vous gardez vos charges utiles propres et légères, cela vous épargnera du time de chargement, en particulier pour les users dont les connections réseau sont faibles. Je recommand le blogpost de Vinay's Sahni, meilleures pratiques pour concevoir une API RESTful pragmatique , pour beaucoup d'informations sur la design et la pagination de l'API RESTful.

Se félicitant des suggestions ou des ajouts à ce qui précède.

J'utilise dispatch_async pour charger datatables de manière asynchronous dans mes cellules de vue de table:

 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); dispatch_async(queue, ^{ NSData *imageData = [NSData dataWithContentsOfURL:url]; dispatch_async(dispatch_get_main_queue(), ^{ UIImage *image = [UIImage imageWithData:imageData]; [imageView setImage:image]; }); }); 

Les images que j'ai utilisées dans cet exemple ne mesuraient que quelques kilo-octets (chacune) et étaient très bien chargées dans la vue de la table.