61 votes

Erreur d'assertion de UICollectionView sur les données périmées

Lorsque j'essaie de décharger un lot d'images de ma vue de la collection et de le remplacer par un autre lot, je rencontre une erreur où, selon que le groupe d'images original ou subséquent était plus ou moins important que le remplacement prévu, une erreur d'assertion se produit et dit :

*** Assertion failure in -[UICollectionViewData validateLayoutInRect:], 
/SourceCache/UIKit_Sim/UIKit-2891.1/UICollectionViewData.m:341
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', 
reason: 'UICollectionView recieved layout attributes for a cell with an 
index path that does not exist: <NSIndexPath: 0xb141c60> {length = 2, path = 0 - 2}

Dans ce cas, la liste d'images existante comptait 5 et la nouvelle liste d'images comptait 2. Ainsi, lorsqu'il est arrivé à la troisième image, l'exception s'est produite, indiquant que le CollectionViewDataDelegate de l'interface utilisateur n'était pas au courant de la modification du flux de données.

Avez-vous des suggestions sur la façon de vous assurer que les nouvelles images seront référencées par l'UICollectionView ? Bien sûr, j'ai appelé 'reloadData'

Merci.

1 votes

Il semble bien que l'objet accède à un vestige de données périmées, d'où la recherche d'une cellule dont l'index peut être hors de portée des données actuelles référencées dans la section. Dans mon cas, après de nombreuses expériences, le remède semble être de "[self.collectionView reloadSections:sections] ;". Après avoir fait cela, les exceptions ne sont plus signalées lorsque je fais glisser le collectionView vers la gauche ou la droite.

0 votes

J'ai un problème similaire. J'ai deux UICV qui affichent les mêmes données. Lorsque l'utilisateur modifie la date dans l'application, je demande de nouvelles données et appelle ensuite reloadData sur les deux CV. Cela fonctionnait très bien jusqu'à iOS6.1. Lorsque je lance les applications sur une version plus récente, j'obtiens l'erreur mentionnée ci-dessus. Le passage à reloadSections:sections la corrige mais ajoute un décalage et une animation indésirables (mise en page de flux personnalisée). Avez-vous fait des progrès dans ce domaine ?

0 votes

Je rencontre ce problème lorsque je renvoie des attributs de mise en page ayant un chemin d'index qui ne devrait pas exister en fonction du nombre de sections et du nombre d'éléments dans chaque section renvoyés par la source de données ! Il m'a fallu un certain temps pour comprendre ce problème. Si vous avez un modèle dynamique, assurez-vous que les chemins des sections/éléments s'alignent sur les chemins des attributs de mise en page.

85voto

Dominic Sander Points 1060

Je rencontre le même problème. Le code fonctionne sous 6.1 et plante sous 7.0. J'ai résolu le problème de la manière suivante :

Dans la fonction

-(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView

J'appelle

[myCollectionView.collectionViewLayout invalidateLayout];

C'est tout.

1 votes

Merci ! Je savais que je devais invalider la mise en page, mais le fait de ne l'appeler que dans cette méthode a fonctionné pour moi.

7 votes

Pour moi, cela a fonctionné d'appeler invalidateLayout juste avant mon appel à reloadData .

1 votes

Quelqu'un peut-il expliquer pourquoi invalidateLayout a réglé le problème ? J'ai eu le même problème lorsque j'ai essayé de changer le dataSource , delegate et collectionViewLayout .

21voto

Beppe Points 1515

Les deux sites Dominic Sander et utilisateur1544494 ont raison et leurs solutions sont bonnes.

Malheureusement, j'ai remarqué que si vous définissez minimumLineSpacingForSectionAtIndex ou minimumInteritemSpacingForSectionAtIndex Si vous n'êtes pas en mesure de le faire, l'apparence de votre collectionView va se briser (tôt ou tard).

Mettez invalidateLayout sur viewWillLayoutSubviews répond à cette question et permet de préserver l'aspect de viewCollection.

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    [viewCollection.collectionViewLayout invalidateLayout];
}

0 votes

J'aime beaucoup cette solution, propre et intuitive. Merci !

4 votes

Après avoir mis cela dans mon contrôleur de vue de collection, j'ai obtenu la méthode -viewWillLayoutSubviews à invoquer à l'infini. Quelle devrait être la hiérarchie des vues pour que cela fonctionne ?

12voto

TopChul Points 156

C'est simple. Tout comme la phrase ci-dessous.

'UICollectionView recieved layout attributes for a cell with an 
index path that does not exist: <NSIndexPath: 0xb141c60> {length = 2, path = 0 - 2}

Cela signifie qu'il n'y a pas d'indexPath(0,2) sur dataSouce. Mais, votre UICollectionViewLayout renvoie un UICollectionViewLayoutAttributes pour indexPath(0,2).

Vous devriez retourner UICollectionViewLayoutAttributes qui n'existe que sur dataSouce.


Je pense que ça a été changé depuis iOS7.

3 votes

Vous avez tout à fait raison. Il faut également mettre à jour la source de données sous-jacente et la mise en page.

0 votes

Mon collègue a trouvé un autre cas le mois dernier. La mise à jour des ContentInsets de UICollectionView entraîne la mise à jour du layout. Donc, (1)dataSourceChanged, (2)setContentInsets -> Crash avec l'exception. (1)dataSourceChanged, (2)reloadData series(Section, insertXXX et ainsi de suite) (3)setContentInsets -> sûr. Ce cas peut être rencontré dans iOS 11.

10voto

Johann Burgess Points 59

Mon problème était que j'avais deux UICollectionViews à l'intérieur UIViewController . Et j'avais à la fois UICollectionViews connecté au même UICollectionViewLayout sous-classe. J'ai résolu ce problème en changeant chaque UICollectionView d'avoir leur propre UICollectionViewLayout sous-classe.

Source : Cette question

0 votes

Tu as sauvé ma journée, mec !

4voto

user1544494 Points 69

J'ai résolu ce problème en mettant à jour la source de données de la vue de la collection :

- (NSInteger)collectionView:(UICollectionView *)collectionView
     numberOfItemsInSection:(NSInteger)section
{
    [collectionView.collectionViewLayout invalidateLayout];
    return collectionArray.count;
}

3 votes

L'appeler lorsque la taille de collectionArray change, pas dans cette méthode.

0 votes

InvalidateLayout ne doit pas être appelé dans une méthode de source de donné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