Assertion failure in -[UICollectionViewData numberOfItemsBeforeSection:]

Josh Katz picture Josh Katz · Oct 14, 2012 · Viewed 12.6k times · Source

Using IOS 6 and the new UICollectionView I have 2 UICollectionViews on the UIViewController and using a Storyboard I get the following error when I click around the UICollectionView I'm not sure why this is happening and Google returns 0 results for this error...

2012-10-13 20:30:06.421 MyApp[768:907] Assertion failure in -[UICollectionViewData numberOfItemsBeforeSection:], /SourceCache/UIKit/UIKit-2372/UICollectionViewData.m:415
2012-10-13 20:30:06.427 MyApp[768:907] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for number of items before section 2147483647 when there are only 1 sections in the collection view'

I'm not using Sections at all and have it set to just 1 section:

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

It happens (appears to be randomly) when I click on on UICollectionView area I have a piece of code to remove element from the UICollectionView:

[tilesArray removeObjectAtIndex:indexPath.row];
[self.tilesCollectionView reloadData];        
[resultsArray addObject:str];
[self.resultsCollectionView reloadData];

Here is how the arrays hooked up to the UICollectionViews

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

    if(collectionView.tag == 2)
        return [resultsArray count];
    else
        return [tilesArray count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    if(collectionView.tag == 2)
    {
        static NSString *cellIdentifier = @"ResultCell";
        ResultCell *cell = (ResultCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

        cell.mainImage.image = [UIImage imageNamed:currentArtContainer.tileMainImage];

        NSString *cellData = [resultsArray objectAtIndex:indexPath.row];
        [cell.titleLabel setText:cellData];

        return cell;
    }
    else
    {
        static NSString *cellIdentifier = @"TileCell";
        TileCell *cell = (TileCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

        cell.topImage.image = [UIImage imageNamed:currentArtContainer.tileTopImage];

        cell.mainImage.image = [UIImage imageNamed:currentArtContainer.tileMainImage];

        NSString *cellData = [tilesArray objectAtIndex:indexPath.row];
        [cell.titleLabel setText:cellData];

        return cell;
    }
}

Please help me resolve this issue. Not even sure how I can catch the exception since it's coming from the UICollectionView internal code. Also forgot to mention I'm using a custom layout for the UICollectionView but I don't know if it's related to this issue.

Thanks again for your help guys!

Edit: I'm getting the exception after all the layout methods are being called... Here is my custom layout... I'm still not sure how to fix it since all my try catch blocks don't trap the error...

- (void)prepareLayout
{
    NSLog(@"In prepareLayout.");

    [super prepareLayout];
    _cellCount = [[self collectionView] numberOfItemsInSection:0];
}

- (CGSize)collectionViewContentSize
{
    NSLog(@"In collectionViewContentSize.");
    @try {

       CGSize csize = [self collectionView].frame.size;
        NSLog(@"In here.");
        return csize;
    }
    @catch(NSException *exception)
    {
        NSLog(@"collectionViewContentSize %@: %@",[exception name],[exception reason]);
    }

}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    @try {

    NSLog(@"In layoutAttributesForItemAtIndexPath. item %d", indexPath.row);


    UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    attributes.size = CGSizeMake(ITEM_SIZE, ITEM_SIZE);

    NSLog(@"firstRun %d", self.firstRun);
    //NSLog(@"panStatus %@", self.panStatus);

    if (self.firstRun == 0) {
        CGFloat x = 0, y = 0;
        CGFloat boundx = self.collectionView.frame.size.width * 0.70;   // Use the whole canvas
        CGFloat boundy = self.collectionView.frame.size.height * 0.70; // Use the whole canvas
        while (x < 50 || x > boundx) x = arc4random() % (int)boundx + indexPath.item;
        while (y < 50 || y > boundy) y = arc4random() % (int)boundy + indexPath.item;

        NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
        if (self.positions)
            dictionary = [self.positions mutableCopy];
        [dictionary setObject:[NSValue valueWithCGPoint:CGPointMake(x, y)] forKey:@(indexPath.item)];
        if (!self.positions)
            self.positions = [[NSDictionary alloc] init];
        self.positions = dictionary;

        attributes.center = CGPointMake(x, y);
    } else if (self.firstRun > 0) {
        CGPoint point = [[self.positions objectForKey:@(indexPath.item)] CGPointValue];
        attributes.center = CGPointMake(point.x, point.y);
    }

    NSLog(@"END layoutAttributesForItemAtIndexPath. item %d", indexPath.row);
        return attributes;

    }
    @catch(NSException *exception)
    {
        NSLog(@"layoutAttributesForItemAtIndexPath %@: %@",[exception name],[exception reason]);
    }
}

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    @try {

    NSLog(@"layoutAttributesForElementsInRect ...");

    NSMutableArray* attributes = [NSMutableArray array];
    for (NSInteger i=0 ; i < self.cellCount; i++) {
        NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:1];
        [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
    }
    NSLog(@"END layoutAttributesForElementsInRect ...");
        return attributes;

    }
    @catch(NSException *exception)
    {
        NSLog(@"layoutAttributesForElementsInRect %@: %@",[exception name],[exception reason]);
    }
}

Answer

Keke picture Keke · Feb 3, 2013

I had this happen when running reloadData from a gesture recognizer, setting delaysTouchesBegan on the gesture recognizer helped.