95 votes

UICollectionView reloadData ne fonctionne pas correctement dans iOS 7

J'ai mis à jour mes applications pour qu'elles fonctionnent sous iOS 7, ce qui se passe bien pour la plupart. J'ai remarqué que dans plus d'une application, le bouton reloadData méthode d'un UICollectionViewController ne se comporte pas tout à fait comme avant.

Je vais charger le UICollectionViewController , remplir le UICollectionView avec quelques données comme d'habitude. Cela fonctionne très bien la première fois. Toutefois, si je demande de nouvelles données (en remplissant le champ UICollectionViewDataSource ), et ensuite appeler reloadData il interrogera la source de données pour numberOfItemsInSection et numberOfSectionsInCollectionView mais il ne semble pas appeler cellForItemAtIndexPath le nombre approprié de fois.

Si je modifie le code pour ne recharger qu'une seule section, alors il fonctionnera correctement. Ce n'est pas un problème pour moi de les modifier, mais je ne pense pas que je doive le faire. reloadData doit recharger toutes les cellules visibles, conformément à la documentation.

Quelqu'un d'autre a vu ça ?

5 votes

Même chose ici, il est dans iOS7GM, il fonctionnait bien avant. J'ai remarqué qu'appeler reloadData après que le viewDidAppear semble résoudre le problème, c'est un horrible contournement, et il faut le corriger. J'espère que quelqu'un pourra vous aider.

1 votes

J'ai le même problème. Le code fonctionnait bien dans iOS6. Maintenant, il n'appelle pas cellforitematindexpath même s'il renvoie le bon nombre de cellules.

0 votes

Ce problème a-t-il été corrigé dans une version postérieure à la 7.0 ?

73voto

Shaunti Fondrisi Points 324

Forcez ceci sur le fil principal :

dispatch_async(dispatch_get_main_queue(), ^ {
    [self.collectionView reloadData];
});

1 votes

Je ne suis pas sûr de pouvoir en dire plus. Après avoir cherché, recherché, testé et sondé. Je pense que c'est un bug d'iOS 7. Forcer le thread principal va exécuter tous les messages liés à UIKit. Je semble rencontrer ce problème lorsque je passe à la vue depuis un autre contrôleur de vue. Je rafraîchis les données sur viewWillAppear. Je pouvais voir les données et l'appel de rechargement de la vue de la collection, mais l'interface utilisateur n'était pas mise à jour. J'ai forcé le fil d'exécution principal (fil d'exécution de l'interface utilisateur) et, comme par magie, cela a commencé à fonctionner. Ceci est seulement dans IOS 7.

6 votes

Cela n'a pas beaucoup de sens, car vous ne pouvez pas appeler reloadData à partir du thread principal (vous ne pouvez pas mettre à jour les vues à partir du thread principal). Il s'agit donc peut-être d'un effet secondaire qui aboutit à ce que vous voulez en raison de certaines conditions de course.

7 votes

La répartition sur la file d'attente principale à partir de la file d'attente principale ne fait que retarder l'exécution jusqu'à la prochaine boucle d'exécution, permettant à tout ce qui est actuellement en file d'attente d'avoir une chance d'être exécuté en premier.

66voto

liamnichols Points 3341

Dans mon cas, le nombre de cellules/sections dans la source de données n'a jamais changé et je voulais juste recharger le contenu visible sur l'écran

J'ai réussi à contourner ce problème en appelant :

[self.collectionView reloadItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]];

alors :

[self.collectionView reloadData];

6 votes

Cette ligne a fait planter mon application - "*** Assertion failure in -[UICollectionView _endItemAnimations], /SourceCache/UIKit_Sim/UIKit-2935.137/UICollectionView.m:3840".

0 votes

@Lugubrious Vous exécutez probablement d'autres animations en même temps. Essayez de les placer dans un fichier de type performBatchUpdates:completion: bloc ?

0 votes

Cela a fonctionné pour moi, mais je ne suis pas sûr de comprendre pourquoi c'est nécessaire. Une idée de la nature du problème ?

26voto

Anton Matosov Points 306

J'ai eu exactement le même problème, mais j'ai réussi à trouver ce qui n'allait pas. Dans mon cas, j'appelais reloadData de la collectionView:cellForItemAtIndexPath : ce qui ne semble pas être correct.

Appel d'envoi de reloadData dans la file d'attente principale a réglé le problème une fois pour toutes.

  dispatch_async(dispatch_get_main_queue(), ^{
    [self.collectionView reloadData];
  });

1 votes

Pouvez-vous me dire à quoi correspond cette ligne pour [self.collectionData.collectionViewLayout invalidateLayout] ;

0 votes

Cela a résolu le problème pour moi aussi - dans mon cas reloadData a été appelé par un observateur de changement.

0 votes

Cela s'applique également à collectionView(_:willDisplayCell:forItemAtIndexPath:)

20voto

miguelsanchez Points 121

Le rechargement de certains articles n'a pas fonctionné pour moi. Dans mon cas, et uniquement parce que la collectionView que j'utilise ne comporte qu'une seule section, je recharge simplement cette section particulière. Cette fois, le contenu est correctement rechargé. Il est étrange que cela ne se produise que sur iOS 7 (7.0.3).

[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];

12voto

user2459624 Points 71

J'ai eu le même problème avec reloadData sous iOS 7. Après une longue session de débogage, j'ai trouvé le problème.

Sous iOS7, reloadData sur UICollectionView n'annule pas les mises à jour précédentes qui ne sont pas encore terminées (mises à jour appelées dans le bloc performBatchUpdates :).

La meilleure solution pour résoudre ce problème est d'arrêter toutes les mises à jour en cours de traitement et d'appeler reloadData. Je n'ai pas trouvé de moyen d'annuler ou d'arrêter un bloc de performBatchUpdates. Par conséquent, pour résoudre ce bogue, j'ai sauvegardé un drapeau qui indique s'il y a un bloc performBatchUpdates en cours de traitement. S'il n'y a pas de bloc de mise à jour en cours de traitement, je peux appeler reloadData immédiatement et tout fonctionne comme prévu. S'il y a un bloc de mise à jour en cours de traitement, je vais appeler reloadData sur le bloc complet de performBatchUpdates.

0 votes

Où effectuez-vous toutes vos mises à jour dans performBatchUpdate ? Certaines en entrée, d'autres en sortie ? Tout en dehors ? Article très intéressant.

0 votes

J'utilise la vue de la collection avec NSFetchedResultsController pour afficher les données de CoreData. Lorsque le délégué du NSFetchedResultsController notifie des changements, je rassemble toutes les mises à jour et les appelle dans performBatchUpdates. Lorsque le prédicat de la requête NSFetchedResultsController est modifié, reloadData doit être appelé.

0 votes

C'est en fait une bonne réponse à la question. Si vous exécutez un reloadItems() (qui est animé) puis un reloadData(), les cellules seront ignorées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X