Existe-t-il un moyen de savoir quand a UITableView
a fini de demander des données à sa source de données?
Aucune des méthodes viewDidLoad
/ viewWillAppear
/ viewDidAppear
du contrôleur de vue associé ( UITableViewController
) n'est utile ici, car elles se déclenchent toutes trop tôt. Aucun d'entre eux ne garantit (tout à fait compréhensible) que les requêtes adressées à la source de données sont terminées pour le moment (par exemple, jusqu'à ce que la vue défile).
Une solution que j'ai trouvé est d'appeler reloadData
à viewDidAppear
, puisque, lorsque les reloadData
rendements, la vue de la table est assuré d'avoir fini d' interroger la source de données autant qu'il doit pour l'instant.
Cependant, cela semble plutôt désagréable, car je suppose que cela oblige la source de données à se voir demander les mêmes informations deux fois (une fois automatiquement et une fois à cause de l' reloadData
appel) lors de son premier chargement.
La raison pour laquelle je veux faire cela est que je veux conserver la position de défilement du UITableView
- mais jusqu'au niveau du pixel, pas seulement jusqu'à la ligne la plus proche.
Lors de la restauration de la position de défilement (en utilisant scrollRectToVisible:animated:
), j'ai besoin que la vue de la table contienne déjà suffisamment de données, sinon l' scrollRectToVisible:animated:
appel de méthode ne fait rien (ce qui se passe si vous placez l'appel seul dans l'un des viewDidLoad
, viewWillAppear
ou viewDidAppear
).
la source
Réponses:
Cette réponse ne semble plus fonctionner, en raison de certaines modifications apportées à l'implémentation de UITableView depuis que la réponse a été écrite. Voir ce commentaire: Être averti lorsque UITableView a fini de demander des données?
Je joue avec ce problème depuis quelques jours et je pense que le sous
UITableView
-classementreloadData
est la meilleure approche:reloadData
ne se termine pas avant que la table n'ait fini de recharger ses données. Ainsi, lorsque le secondNSLog
est déclenché, la vue de table a en fait fini de demander des données.J'ai sous-classé
UITableView
pour envoyer des méthodes au délégué avant et aprèsreloadData
. Il fonctionne comme un charme.la source
reloadData
revient immédiatement et je vois "END reloadData" avant que les cellules ne soient réellement rechargées (c'est-à-dire avant que lesUITableViewDataSource
méthodes ne soient appelées). Mon expérimentation démontre exactement le contraire de ce que vous dites. Je dois mal comprendre ce que vous essayez de dire.[super reloadData]
fonctionne pour moi:dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"reload complete");});
. Cela saute essentiellement aux blocs qui sont affichés par la vue de la tablereloadData
.J'ai eu le même scénario dans mon application et j'ai pensé publier ma réponse pour vous les gars, car les autres réponses mentionnées ici ne fonctionnent pas pour moi pour iOS7 et versions ultérieures
Enfin, c'est la seule chose qui a fonctionné pour moi.
Mise à jour rapide:
Alors, comment cela fonctionne.
Fondamentalement, lorsque vous rechargez, le thread principal devient occupé, donc à ce moment-là, lorsque nous effectuons un thread async de répartition, le bloc attendra que le thread principal soit terminé. Donc, une fois que la tableview a été complètement chargée, le thread principal se terminera et il enverra donc notre bloc de méthode
Testé sous iOS7 et iOS8 et cela fonctionne à merveille ;)
Mise à jour pour iOS9: Cela fonctionne très bien avec iOS9 également. J'ai créé un exemple de projet dans github en tant que POC. https://github.com/ipraba/TableReloadingNotifier
Je joins ici la capture d'écran de mon test.
Environnement testé: simulateur iOS9 iPhone6 de Xcode7
la source
EDIT: Cette réponse n'est en fait pas une solution. Cela semble probablement fonctionner au début car le rechargement peut se produire assez rapidement, mais en fait, le bloc d'achèvement n'est pas nécessairement appelé une fois que le rechargement des données est complètement terminé - car reloadData ne se bloque pas. Vous devriez probablement chercher une meilleure solution.
Pour développer la réponse de @Eric MORAND, mettons un bloc de complétion. Qui n'aime pas un bloc?
et...
Usage:
la source
dispatch_async(dispatch_get_main_queue(), ^{completionBlock();});
. Ce saut saute essentiellement dans les blocs affichés par la vue de la tablereloadData
.reloadData demande simplement des données pour les cellules visibles. Dit, pour être averti lorsque la partie spécifiée de votre table est chargée, veuillez accrocher la
tableView: willDisplayCell:
méthode.la source
Telle est ma solution. 100% fonctionne et utilisé dans de nombreux projets. C'est une simple sous-classe UITableView.
C'est similaire à la solution de Josh Brown à une exception près. Aucun délai n'est nécessaire dans la méthode performSelector. Peu importe le temps qu'il
reloadData
faut.tableViewDidLoadData:
se déclenche toujours lorsque voustableView
avez fini de demanderdataSource
cellForRowAtIndexPath
.Même si vous ne voulez pas de sous-classe,
UITableView
vous pouvez simplement appeler[performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]
et votre sélecteur sera appelé juste après le rechargement de la table. Mais vous devez vous assurer que le sélecteur n'est appelé qu'une seule fois par appel àreloadData
:Prendre plaisir. :)
la source
performSelector
ou s'exécutant sur le thread principal avecdispatch_asynch
ne fonctionnent pas sous iOS 9 .C'est une réponse à une question légèrement différente: j'avais besoin de savoir quand
UITableView
j'avais également fini d'appelercellForRowAtIndexPath()
. J'ai souslayoutSubviews()
-classé (merci @Eric MORAND) et ajouté un rappel de délégué:SDTableView.h:
SDTableView.m:
Usage:
MyTableViewController.h:
MyTableViewController.m:
REMARQUES: Comme il s'agit d'une sous-classe
UITableView
dont une propriété de délégué pointe déjà,MyTableViewController
il n'est pas nécessaire d'en ajouter une autre. Le "délégué @dynamic" indique au compilateur d'utiliser cette propriété. (Voici un lien décrivant ceci: http://farhadnoorzay.com/2012/01/20/objective-c-how-to-add-delegate-methods-in-a-subclass/ )La
UITableView
propriété dansMyTableViewController
doit être modifiée pour utiliser la nouvelleSDTableView
classe. Cela se fait dans l'inspecteur d'identité d'Interface Builder. Sélectionnez l'UITableView
intérieur duUITableViewController
et réglez sa "Classe personnalisée" surSDTableView
.la source
J'avais trouvé quelque chose de similaire pour recevoir une notification de changement
contentSize
deTableView
. Je pense que cela devrait également fonctionner ici, car contentSize change également avec le chargement des données.Essaye ça:
En
viewDidLoad
écriture,et ajoutez cette méthode à votre viewController:
Vous pourriez avoir besoin de légères modifications lors de la vérification des modifications. Cela avait fonctionné pour moi cependant.
À votre santé! :)
la source
-viewWillAppear
et supprimez-vous dans la-viewWillDisapear
méthode.Voici une solution possible, bien que ce soit un hack:
Où votre
-scrollTableView
méthode fait défiler la vue du tableau avec-scrollRectToVisible:animated:
. Et, bien sûr, vous pouvez configurer le délai dans le code ci-dessus de 0,3 à tout ce qui semble fonctionner pour vous. Ouais, c'est ridiculement piraté, mais ça marche pour moi sur mon iPhone 5 et 4S ...la source
J'avais quelque chose de similaire, je crois. J'ai ajouté un BOOL comme variable d'instance qui me dit si l'offset a été restauré et l'enregistre
-viewWillAppear:
. Lorsqu'il n'a pas été restauré, je le restaure dans cette méthode et définissez le BOOL pour indiquer que j'ai récupéré le décalage.C'est une sorte de hack et cela peut probablement être mieux fait, mais cela fonctionne pour moi pour le moment.
la source
-viewDidLoad
(où cela devrait se produire bien sûr) mais cela ne fonctionnait que lorsque je définissais le décalage animé. En déplaçant le réglage du décalage,-viewWillAppear:
cela fonctionnait, mais je devais maintenir un drapeau pour ne le définir qu'une seule fois. Je suppose que la vue de table recharge ses données une fois ajoutées à une vue, donc c'est déjà dedans-loadView
. Êtes-vous sûr que vos données sont disponibles lors du chargement de la vue? Ou est-il chargé dans un thread séparé ou quelque chose?Il semble que vous souhaitiez mettre à jour le contenu des cellules, mais sans les sauts soudains qui peuvent accompagner les insertions et les suppressions de cellules.
Il existe plusieurs articles sur ce sujet. C'est un.
Je suggère d'utiliser setContentOffset: animated: au lieu de scrollRectToVisible: animated: pour les paramètres au pixel près d'une vue de défilement.
la source
Vous pouvez essayer la logique suivante:
Et avant d'appeler reloadData, définissez prevIndexPath sur nil. Comme:
J'ai testé avec NSLogs, et cette logique semble correcte. Vous pouvez personnaliser / améliorer au besoin.
la source
enfin j'ai fait fonctionner mon code avec ceci -
il y avait peu de choses dont il fallait s'occuper -
- (UITableViewCell *)MyTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
"la source
Vous pouvez redimensionner votre tableview ou définir sa taille de contenu dans cette méthode lorsque toutes les données sont chargées:
la source
Je viens d'exécuter une minuterie planifiée répétée et de l'invalider uniquement lorsque la taille de contenu de la table est plus grande lorsque la hauteur de tableHeaderView (signifie qu'il y a du contenu de lignes dans la table). Le code en C # (monotouch), mais j'espère que l'idée est claire:
la source
N'est-il pas
UITableView
layoutSubviews
appelé juste avant que la vue de tableau affiche son contenu? J'ai remarqué qu'il est appelé une fois que la vue table a fini de charger ses données, vous devriez peut-être enquêter dans cette direction.la source
Depuis iOS 6, la
UITableview
méthode déléguée a appelé:s'exécutera une fois que votre table sera rechargée avec succès. Vous pouvez effectuer la personnalisation selon les besoins dans cette méthode.
la source
La meilleure solution que j'ai trouvée dans Swift
la source
Pourquoi ne pas simplement prolonger?
faites défiler jusqu'à la fin:
Non testé avec beaucoup de données
la source