Problèmes d'insertion dans la section UICollectionView qui contient un pied de page

J'ai un UICollectionView typique qui utilise UICollectionViewFlowLayout de manière verticale. J'utilise une API de repos avec pagination pour remplir la vue de collection. Afin de triggersr la prochaine page à download, j'utilise le délégué lorsqu'il request la layout du pied de page:

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSSsortingng *)kind atIndexPath:(NSIndexPath *)indexPath{ RDLoadMoreReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"RDLoadMoreReusableView" forIndexPath:indexPath]; view.delegate = self; [view start]; [self loadNextPageOfAssets]; return view; } 

Voici le code derrière mon loadNextPageOfAssets:

 -(void)loadNextPageOfAssets{ __weak RDRadiusGridViewController *weakSelf = self; // Increment page and request assets. They are added to cluster.assets before the completion block is called. self.cluster.pagination.page++; [self.cluster requestAssetsWithCompletionBlock:^(NSArray *assets) { SM_LOG_DEBUG(@"page.total: %ld assets.count: %ld", self.cluster.pagination.totalCount, (long)assets.count); NSMutableArray *indexPaths = [[NSMutableArray alloc]initWithCapacity:assets.count]; for(NSUInteger index = 0; index < assets.count; index++){ NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.cluster.assets.count - assets.count + index inSection:0]; SM_LOG_DEBUG(@"Inserting indexPath: %ld:%ld", (long)indexPath.item, (long)indexPath.section); [indexPaths addObject:indexPath]; } [weakSelf.collectionView performBatchUpdates:^{ [weakSelf.collectionView insertItemsAtIndexPaths:indexPaths]; } completion:^(BOOL finished) { }]; // [weakSelf.collectionView reloadData]; }]; } 

Quand je cours je peux aller à mon ViewController et voir la première page des capitaux chargés. Si je défile vers le bas, je verrai la vue du pied de page (qui contient un spinner), mais le code se cassera au sharepoint rupture de l'exception à la ligne:

 [weakSelf.collectionView insertItemsAtIndexPaths:indexPaths]; 

Échec de l'assertion dans – [UICollectionViewData layoutAtsortingbutesForSupplementaryElementOfKind: atIndexPath:], /SourceCache/UIKit/UIKit-3185.20/UICollectionViewData.m:829


Ensuite, si je continue, il se bloque avec l'erreur:

2014-06-11 16: 39: 58.335 Radius-iOS [4901: 525006] * Terminaison de l'application due à une exception non interceptée 'NSInternalInconsistencyException', raison: 'aucune instance de UICollectionViewLayoutAtsortingbutes pour -layoutAtsortingbutesForSupplementaryElementOfKind: UICollectionElementKindSectionFooter au path {longueur = 2, path = 0 – 0} '* Première stack d'appels:


Cela me dérange. layoutAtsortingbutesForSupplementaryElementOfKind sonne comme si c'était quelque chose à voir avec la class de layout, mais je n'utilise pas une layout de stream personnalisée plutôt que celle fournie par défaut. On dirait que le code d'Apple est fou mais je sens que j'utilise tout correctement.

Maintenant, si je déplace l'appel:

 [self loadNextPageOfAssets]; 

de la cellule supplémentaire dequeue vers le file UICollectionViewCell deque, et supprimez les vues de pied de page toutes set, alors l'insert fonctionne très bien.

Pour l'instant j'appelle reloadData au lieu de insert, mais c'est UGLY.

Suis-je en train de négliger quelque chose à propos des pieds de page?

La réponse fournie par VaporwareWolf est un peu un hack. En returnnant une taille minuscule au lieu d'une taille nulle, la vue supplémentaire existera toujours mais à une taille trop petite pour voir. Voilà pourquoi il corrige l' exception NSInternalInconsistencyException

Mais, il y a une vraie solution .

Après avoir ajouté datatables à la source de données et avant d' appeler insertItemsAtIndexPaths , invalidez simplement la layout de la collection pour la rendre insertItemsAtIndexPaths aux modifications.

Objectif c

 [self.collectionView.collectionViewLayout invalidateLayout] 

Rapide

 collectionView.collectionViewLayout.invalidateLayout() 

Il se trouve que j'étais en train de rencontrer un problème de layout (comme le suggère la description de l'erreur)

 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section{ if(<myDecision>){ return CGSizeZero; } else { return CGSizeMake(320, 50); } } 

CGSizeZero est ce qui causait le crash. Au lieu de cela, utilisez CGSizeMake (0.001, 0.001). C'est le seul changement nécessaire. Il fonctionne comme prévu maintenant.

Il y a un énorme article en russe sur les bugs dans UICollectionView: http://habrahabr.ru/post/211144/ .

Voici quelques methods de cet article qui peuvent résoudre votre problème:

 @try { [self.collectionView insertItemsAtIndexPaths:indexPaths]; } @catch (NSException *exception) {} 

ou

 [self.collectionView performBatchUpdates:^{ [self.collectionView reloadData]; } completion:nil]; 

Vous devez implémenter les deux methods (en-tête et pied de page). Même si vous n'en voulez qu'un. Regarde mon code

 -(UICollectionReusableView *) collectionView:(UICollectionView *) collectionView viewForSupplementaryElementOfKind:(NSSsortingng *) kind atIndexPath:(NSIndexPath *) indexPath { UICollectionReusableView *header = [[UICollectionReusableView alloc] init]; if ([kind isEqualToSsortingng:UICollectionElementKindSectionHeader]) { header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionViewHeader" forIndexPath:indexPath]; } else { header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionViewHeader" forIndexPath:indexPath]; } return header; } -(CGSize) collectionView:(UICollectionView *) collectionView layout:(UICollectionViewLayout *) collectionViewLayout referenceSizeForHeaderInSection:(NSInteger) section { return CGSizeMake(self.view.frame.size.width, 100); } -(CGSize) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section { return CGSizeZero; }