web-dev-qa-db-fra.com

Échec d'assertion dans UICollectionViewData indexPathForItemAtGlobalIndex

J'utilise performBatchUpdates () pour mettre à jour la vue de ma collection, où je procède à un rafraîchissement complet, c'est-à-dire que je supprime ce qui s'y trouvait et que je réinsère tout. Les mises à jour par lots sont effectuées dans le cadre d'un Observer associé à une NSMutableArray (bingDataItems).

cellItems est le tableau contenant les éléments qui sont ou seront insérés dans la vue Collection.

Voici le code:

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    cultARunner *_cultARunner = [cultARunner getInstance];
    if ( [[_cultARunner bingDataItems] count] ) {
        [self.collectionView reloadData];
        [[self collectionView] performBatchUpdates: ^{

            int itemSize = [cellItems count];
            NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];

            // first delete the old stuff
            if (itemSize == 0) {
                [arrayWithIndexPaths addObject: [NSIndexPath indexPathForRow: 0 inSection: 0]];
            }
            else {
                for( int i = 0; i < cellItems.count; i++ ) {
                    [arrayWithIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
                }
            }
            [cellItems removeAllObjects];
            if(itemSize) {
                [self.collectionView deleteItemsAtIndexPaths:arrayWithIndexPaths];
            }

            // insert the new stuff
            arrayWithIndexPaths = [NSMutableArray array];
            cellItems = [_cultARunner bingDataItems];
            if ([cellItems count] == 0) {
                [arrayWithIndexPaths addObject: [NSIndexPath indexPathForRow: 0 inSection: 0]];
            }
            else {              
                for( int i = 0; i < [cellItems count]; i++ ) {
                    [arrayWithIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
                }
            }
            [self.collectionView insertItemsAtIndexPaths:arrayWithIndexPaths];
        }
        completion:nil];
    }
}

Je reçois cette erreur, mais pas toutes les fois (pourquoi?)

2012-12-16 13:17:59.789 [16807:19703] *** Assertion failure in -[UICollectionViewData indexPathForItemAtGlobalIndex:], /SourceCache/UIKit_Sim/UIKit-2372/UICollectionViewData.m:442
2012-12-16 13:17:59.790 [16807:19703] DEBUG:    request for index path for global index 1342177227 when there are only 53 items in the collection view

J'ai vérifié le seul fil de discussion qui mentionnait le même problème ici: Échec de l'assertion UICollectionView Assert , mais il n'est pas très clair que faire [collectionview reloadData] ne soit pas recommandé dans le bloc performBatchUpdates().

Des suggestions sur ce qui pourrait mal se passer ici?

26
DancingJohn

Finalement! Ok, voici ce qui a causé ce crash pour moi.

Comme indiqué précédemment, je créais des vues supplémentaires afin de fournir des en-têtes de section personnalisés pour ma vue de collection. 

Le problème est le suivant: il apparaît que la propriété indexPath d'une vue supplémentaire DOIT correspondre à la propriété indexPath d'une cellule existante de la collection. Si le chemin d'index de la vue supplémentaire n'a pas de cellule ordinaire correspondante, l'application se bloque. Je pense que la vue de collection tente de récupérer des informations pour la cellule d'une vue supplémentaire pour une raison quelconque pendant la procédure de mise à jour. Il se bloque quand il ne peut pas en trouver un.

Espérons que cela résoudra aussi votre problème!

20
Ash

Voici la solution de contournement appropriée à cet accident:

Chacune de vos vues supplémentaires est associée à un certain chemin d'index. Si vous ne disposez pas d'une cellule dans ce chemin d'index (chargement initial, vous avez supprimé la ligne, etc.), renvoyez une hauteur de 0 pour votre vue supplémentaire via le délégué de votre présentation. 

Donc, pour une mise en page de flux, implémentez UICollectionViewDelegateFlowLayout

(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section

méthode (et la méthode de pied de page correspondante, si vous utilisez des pieds de page) avec la logique suivante

if ( you-have-a-cell-at-the-row-for-this-section )
    return myNormalHeaderSize;
else return CGSizeMake( 0,0 );

J'espère que cela t'aides!

17
deepseadiving

reloadData ne fonctionne pas pour moi, car le seul but de performBatchUpdates est d’animer les modifications. Si vous utilisez reloadData, vous actualisez uniquement les données, mais sans animations.

Ainsi, les suggestions de "remplacer performBatchUpdates par reloadData" signifie à peu près "abandonnez ce que vous essayez de faire".

Je suis désolé, je suis simplement frustré parce que cette erreur me revient constamment lorsque j'essaye de faire de superbes mises à jour animées et que mon modèle est correct à 100%. solutions complètement.

Mon opinion est que les vues de collection sont toujours boguées et ne peuvent pas effectuer de rafraîchissements animés compliqués, même si elles devraient pouvoir le faire. Parce que c'était la même chose pour les vues de table, mais celles-ci sont maintenant assez stables (cela a pris du temps, cependant).

// Edition (1 er septembre 2013) Le bogue signalé étant maintenant fermé, ce problème semble déjà avoir été résolu par Apple.

8
czechboy

J'ai eu le même problème.

J'ai essayé plusieurs variantes, mais la dernière solution qui semble fonctionner est [self.collectionView reloadData], où "self.collectionView" est le nom de votre vue de collection.

J'ai essayé les méthodes suivantes, directement issues de la "Référence de classe UICollectionView": insertion, déplacement et suppression d'éléments.

Celles-ci ont d'abord été utilisées pour "déplacer" l'élément d'une section à une autre.

  • deleteItemsAtIndexPaths:

  • insertItemsAtIndexPaths:

Ensuite, j'ai essayé moveItemAtIndexPath:toIndexPath:.

Ils ont tous généré l'erreur suivante:

Échec d'assertion dans - [UICollectionViewData indexPathForItemAtGlobalIndex:], /SourceCache/UIKit_Sim/UIKit-2372/UICollectionViewData.m:442

Alors, essayez la méthode "reloadData".

3
Jim

Si vous supprimez la dernière cellule d'une section contenant un en-tête/un pied de page, le bogue apparaît.

J'ai essayé de renvoyer nil pour la taille d'en-tête/pied de page/élément à ce moment-là et ceci parfois corrige le problème.

Options:

  1. Rechargez la vue de table entière au lieu d’animer la suppression du dernier élément.
  2. Ajoutez une cellule de base invisible supplémentaire avec une taille inférieure à 1.
2
HeikoG

Une erreur de cheeseball pouvant entraîner cette erreur est de réutiliser le même UICollectionViewFlowLayout sur plusieurs collectionViews sur le même contrôleur de vue! Il suffit d’initier différents flowLayouts pour chaque vue de collection et vous serez prêt à partir!

2
ColossalChris

J'ai rencontré ce problème lorsque j'ai supprimé une des cellules de ma vue de collection.

Le problème était que j'utilisais une disposition personnalisée et que l'appel layoutAttributesForElementsInRect renvoyait plus que le nombre de cellules de la vue Collection après la suppression. 

Apparemment, UICollectionView se contente de parcourir le tableau renvoyé par la méthode sans vérifier le nombre de cellules.

La modification de la méthode pour renvoyer le même nombre d'attributs de présentation a résolu l'incident.

1
Allen Zeng

Je ne pouvais toujours pas comprendre comment l'incrément global était tellement incrémenté, mais j'ai résolu mon problème en insérant un élément temporaire dans le tableau de source de données sous-jacent, à savoir cellItems et en appelant [self.collectionview reloadData] dans viewDidLoad().

Cela insère temporairement une cellule de marque de réservation dans la vue de collection jusqu'à ce que je déclenche le processus réel à l'aide de performBatchUpdates().

0
DancingJohn