8

Ho un UICollectionView tipico che utilizza UICollectionViewFlowLayout in modo verticale. Sto usando un'API di riposo con paginazione per popolare la vista raccolta. Al fine di attivare la pagina successiva per scaricare, sto usando il delegato quando chiede per il layout piè di pagina:Problemi che si inseriscono nella sezione UICollectionView che contiene un piè di pagina

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

Ecco il codice dietro le mie 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]; 
    }]; 
} 

Quando eseguo mi posso andare al mio ViewController e vedere la prima pagina delle risorse caricate. Se ho scorrere verso il basso vedrò la vista piè di pagina (che contiene un filatore), ma poi il codice pausa al punto di rottura un'eccezione alla riga:

[weakSelf.collectionView insertItemsAtIndexPaths:indexPaths]; 

errore di asserzione in - [UICollectionViewData layoutAttributesForSupplementaryElementOfKind: atIndexPath:] , /SourceCache/UIKit/UIKit-3185.20/UICollectionViewData.m:829


Poi se continuo si blocca con l'errore:

2014/06/11 16: 39: 58,335 Radius-iOS [ 4901: 525006] * Termina l'applicazione a causa di eccezione non identificata 'NSInternalInconsistencyException', la ragione: 'nessuna istanza UICollectionViewLayoutAttributes per -layoutAttributesForSupplementaryElementOfKind: UICollectionElementKindSectionFooter al sentiero {lunghezza = 2, il percorso = 0 - 0}' * primo stack di chiamate tiro:


Questo è sconcertante per me. layoutAttributesForSupplementaryElementOfKind suona come se avesse a che fare con la classe di layout, ma non sto usando un layout di flusso personalizzato piuttosto quello predefinito fornito. Sembra che il codice Apple sia pazzo, ma sento che sto usando tutto correttamente.

Ora, se mi muovo la chiamata:

[self loadNextPageOfAssets]; 

dal dequeue cellulare supplementare alla teh UICollectionViewCell deque, e rimuovere i punti di vista del piè di pagina tutti insieme, poi l'inserto funziona alla grande.

Per ora sto chiamando reloadData invece di insert, ma questo è UGLY.

Sto trascurando qualcosa sui footer?

+0

wel .. per cominciare si potrebbe verificare ciò che è l'elemento integrativo tipo che viene passato in viewForSupplementaryElementOfKind – govi

risposta

8

La risposta fornita da VaporwareWolf è un po 'incisiva. Restituendo una dimensione piccola invece di una dimensione zero, la vista supplementare esisterà sempre ma con una dimensione troppo piccola per essere vista. Ecco, questo è il motivo per cui si risolve il NSInternalInconsistencyException

Ma, c'è una vera soluzione.

Dopo aggiungendo i dati all'origine dati e prima chiamare insertItemsAtIndexPaths, semplicemente invalidando il layout sul CollectionView per metterlo a conoscenza delle modifiche.

Objective-C

[self.collectionView.collectionViewLayout invalidateLayout] 

Swift

collectionView.collectionViewLayout.invalidateLayout() 
+0

Sarò d'accordo con te. Ho imparato molto su UICollectionView da quando ho fatto questo post anni fa. Cambiando questo alla risposta accettata. – VaporwareWolf

+0

Grazie per l'ottima risposta. Anch'io sto affrontando lo stesso problema. Utilizzare il layout personalizzato predefinito e restituire CGSizeZero per la vista footer quando l'origine dati è vuota. L'app si arresterà in modo anomalo se non chiamo invalidateLayout prima di inserire o spostare metodi – PrimaryChicken

0

C'è un enorme articolo in russo sui bug in UICollectionView: http://habrahabr.ru/post/211144/.

Qui ci sono un paio di metodi di tale articolo che può risolvere il problema:

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

o

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

è necessario implementare entrambi i metodi (intestazione e piè di pagina). Anche se ne vuoi solo uno.Guardate il mio codice

-(UICollectionReusableView *) collectionView:(UICollectionView *) collectionView 
      viewForSupplementaryElementOfKind:(NSString *) kind 
           atIndexPath:(NSIndexPath *) indexPath 
{ 
    UICollectionReusableView *header = [[UICollectionReusableView alloc] init]; 

    if ([kind isEqualToString: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; 
} 
8

Si scopre che in realtà stavo sperimentando un problema con il layout (come la descrizione di errore suggerisce)

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

CGSizeZero è quello che stava causando l'incidente. Utilizzare invece CGSizeMake (0,001, 0,001). Questo è l'unico cambiamento necessario. Funziona come previsto ora.

+1

Grazie per questo! Qualche ragione per cui non si può semplicemente restituire CGSizeZero? E 'estremamente fastidioso dover gestire i capricci della collezione :( – akdsouza

+0

che è stato super frustrante ma questo lo ha risolto grazie! :) – agandi

Problemi correlati