web-dev-qa-db-fra.com

Redessiner UITableView après la mise à jour des données async

J'ai un UITableview que je charge avec async de données afin que la tableview puisse apparaître sans données.
J'ai fatigué la méthode ReloadData mais la vue table reste vide tant que je n'ai pas fait défiler la vue table, les données apparaissent soudainement.
La même chose se produit lorsque je charge une vue sous forme de vue détaillée et que je passe d’un élément à l’autre, les données relatives aux éléments précédents apparaissent en premier et dès que je fais défiler le tableau, elles affichent les données correctes.
Je suppose que la méthode ReloadData fonctionne très bien, mais je dois redessiner la vue de la table d’une manière ou d’une autre, des suggestions sur la façon de résoudre ce problème? 

/Jimmy

24
Jimmy Engtröm

Vous avez dit que vous remplissiez le contenu de manière asynchrone, mais avez-vous appelé reloadData dans le contexte du thread principal? (et pas via le fil qui remplit le contenu)

Objectif c

[yourUITableView performSelectorOnMainThread:@selector(reloadData)
                                  withObject:nil 
                               waitUntilDone:NO];

Rapide

dispatch_async(dispatch_get_main_queue(), { self.tableView.reloadData() })

Monotouch

InvokeOnMainThread(() => this.TableView.ReloadData());
54
yonel

Yonels answer est parfait lorsque votre vue est actuellement visible pour l'utilisateur (par exemple: l'utilisateur appuie sur un bouton de rechargement qui remplit votre UITableView.)

Toutefois, si vos données sont chargées de manière asynchrone et que votre UITableView n'est pas visible pendant la mise à jour (par exemple: vous ajoutez des données à votre UITableView dans une autre vue et la UITableView est affichée ultérieurement par l'utilisateur), remplacez simplement la méthode UITableViewController 's viewWillAppear.

- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.tableView reloadData];
}

L'effet positif est que votre UITableView ne recharge ses données qu'une seule fois, lorsque l'utilisateur souhaite réellement les voir, pas lorsque de nouveaux éléments sont ajoutés.

4
Jannis

Je suppose que ça n'a pas été rechargé.

Lorsque vous faites défiler les cellules pour sortir de l'écran, alors…

tableView: cellForRowAtIndexPath:

…sera appelé. Donc, il sera rechargé.

Je suppose que la variable UITableView n'est pas validée.

Si vous utilisez UITableView comme vue principale, vous pouvez essayer ceci.

[self.view reloadData];

ou

[self.tableView reloadData];

2
Joey

J'avais le même problème aujourd'hui (Storyboard sous iOS 7.0). J'utilisais table View dans un UIViewController.Lorsque la vue était chargée, tout fonctionnait correctement. tous les délégués ont été appelés. Lorsque la source de données sous-jacente (dans mon cas, Array) a été modifiée; les lignes visibles du tableau ne sont pas mises à jour. Elles ont été mises à jour; seulement quand je faisais défiler la vue de table.

J'ai tout essayé appeler reloadData sur le thread principal, appeler reload dans ViewWillAppear; rien n'a fonctionné.

Le problème que j'ai trouvé; était que je n'avais pas fait la connexion dans le storyboard; pour la vue de table avec la référence Outlet.La source de données et le délégué ont été définis cependant. Je ne pensais pas que cela pouvait être le problème; comme tout fonctionnait bien du premier coup.

J'espère que ça aide quelqu'un.J'ai eu du mal à le découvrir.

2
RUppal

Après avoir copié naïvement dans la solution de yonel et l'avoir qualifiée de bonne, j'ai compris que l'appel de performSelectorOnMainThread:withObject:waitUntilDone: corrigeait le symptôme, mais pas le problème. Le plus gros problème est que vous effectuez des mises à jour d'interface utilisateur tout en restant dans le contexte du thread asynchrone ou d'arrière-plan.

Voici à quoi ressemblait mon code:

dispatch_queue_t queue = dispatch_queue_create("com.kyleclegg.myqueue", NULL);
dispatch_async(queue, ^{

  // Make API call
  // Retrieve data, parse JSON, update local properties
  // Make a call to reload table data

});

Quand cela devrait ressembler à ceci:

dispatch_queue_t queue = dispatch_queue_create("com.kyleclegg.myqueue", NULL);
dispatch_async(queue, ^{

  // Make API call
  // Retrieve data, parse JSON, update local properties

  dispatch_async(dispatch_get_main_queue(), ^{
    // Now make the call to reload data and make any other UI updates
    [self.tableView reloadData]
  });

});

Si le only vous devez appeler [self.tableView reloadData], vous pouvez probablement utiliser performSelectorOnMainThread:withObject:waitUntilDone: car il remplit le même objectif, mais vous devez également reconnaître ce qui se passe dans l’ensemble. De même, si vous effectuez plus de travail d'interface utilisateur que de simplement recharger la table, tout ce code doit également être placé dans la file d'attente principale.

Référence: Un exemple concis d'utilisation de GCD et de la gestion de l'arrière-plan par rapport au thread principal.

0
Kyle Clegg

Swift 4:

DispatchQueue.main.async { self.tableView.reloadData() }
0
Nate Uni