8

Ich habe eine typische UICollectionView, die UICollectionViewFlowLayout in einer vertikalen Weise verwendet. Ich verwende eine Rest-API mit Paginierung, um die Sammlungsansicht zu füllen. Um die nächste Seite zu triggern zum Download, ich bin mit dem Delegaten, wenn es für das Fußzeile Layout fragt:Probleme beim Einfügen in UICollectionView-Abschnitt, der eine Fußzeile enthält

- (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; 
} 

Hier ist der Code hinter meinem 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]; 
    }]; 
} 

Wenn ich laufe mich kann zu meinem ViewController gehen und die erste Seite der geladenen Assets sehen. Wenn ich ich nach unten scrollen, werden die Fußzeile Ansicht sehen (die einen Spinner enthält), aber dann wird der Code an der Ausnahme Bruchstelle an der Linie brechen:

[weakSelf.collectionView insertItemsAtIndexPaths:indexPaths]; 

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


Dann, wenn ich weiterhin mit dem Fehler abstürzt:

2014-06-11 16: 39: 58,335 Radius-iOS [ 4901: 525006] * App beenden wegen abgefangene Ausnahme 'NSInternalInconsistencyException', Grund: 'nein UICollectionViewLayoutAttributes Beispiel für -layoutAttributesForSupplementaryElementOfKind: UICollectionElementKindSectionFooter bei Wegs {Länge = 2, path = 0 - 0}' * ersten Wurf Call-Stack:


Dies ist rätselhaft mich. layoutAttributesForSupplementaryElementOfKind klingt, als ob es etwas mit der Layout-Klasse zu tun hat, aber ich verwende kein benutzerdefiniertes Flow-Layout, sondern das Standard-Layout. Es klingt, als wäre Apples Code verrückt, aber ich fühle, dass ich alles richtig benutze.

Nun, wenn ich mich bewege den Anruf:

[self loadNextPageOfAssets]; 

von der Zusatz Zelle dequeue UICollectionViewCell deque, und entfernen Sie die Fußzeile Ansichten alle zusammen an teh, dann der Einsatz funktioniert super.

Für jetzt rufe ich reloadData anstelle von einfügen, aber das ist UGLY.

Betrachte ich etwas über die Fußzeilen?

+0

wel .. für den Anfang könnte man prüfen, was das Zusatzelement ist eine Art, die in viewForSupplementaryElementOfKind – govi

Antwort

8

Die Antwort von VaporwareWolf ist ein bisschen wie ein Hack. Durch das Zurückgeben einer kleinen Größe anstelle einer Größe von Null wird die ergänzende Ansicht immer vorhanden sein, jedoch in einer Größe, die zu klein ist, um sie zu sehen. Also das ist, warum es behebt das NSInternalInconsistencyException

Aber gibt es eine wirkliche Lösung.

Nach Hinzufügen der Daten an die Datenquelle und vorinsertItemsAtIndexPaths Aufruf ungültig macht nur das Layout auf der Kollektion, um es über die Änderungen aufmerksam zu machen.

Objective-C

[self.collectionView.collectionViewLayout invalidateLayout] 

Swift

collectionView.collectionViewLayout.invalidateLayout() 
+0

Ich stimme dir zu. Ich habe viel über UICollectionView gelernt, seit ich diesen Beitrag vor Jahren gemacht habe. Ändere dies zur akzeptierten Antwort. – VaporwareWolf

+0

Danke für die tolle Antwort. Ich habe auch das gleiche Problem. Verwenden des benutzerdefinierten Standardlayouts und Zurückgeben von CGSizeZero für meine Fußzeilenansicht, wenn die Datenquelle leer ist. Die App wird abstürzen, wenn ich InvalidateLayout vor dem Einfügen oder Verschieben Methoden nicht aufrufen – PrimaryChicken

0

Es gibt einen großen Artikel auf Russisch über Fehler in UICollectionView: http://habrahabr.ru/post/211144/.

Hier sind ein paar Methoden aus diesem Artikel, die Ihr Problem lösen kann:

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

oder

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

Sie sollten implementieren beide (Kopf- und Fußzeile) Methoden. Selbst wenn Sie nur einen wollen.Sehen Sie sich meinen Code

-(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

Es stellt sich heraus, dass ich tatsächlich wurde ein Problem mit dem Layout zu erfahren (wie die Fehlerbeschreibung deutet darauf hin)

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

CGSizeZero ist, was den Absturz verursacht wurde. Verwenden Sie stattdessen CGSizeMake (0,001, 0,001). Das war die einzige Änderung, die notwendig war. Es läuft jetzt wie beabsichtigt.

+1

Vielen Dank für diese geführt wird! Warum kann man CGSizeZero nicht einfach zurückgeben? Es ist extrem nervig, die Wutanfälle der Sammelansicht zu behandeln :( – akdsouza

+0

das war super frustrierend, aber das sortierte es dank! :) – agandi