-[UICollectionViewData numberOfItemsBeforeSection:]中的断言失败

14

使用IOS 6和新的UICollectionView,我在UIViewController上有2个UICollectionView并使用了Storyboard。当我在UICollectionView中点击时,出现以下错误。我不确定为什么会发生这种情况,而且谷歌搜索也没有返回任何此错误的结果...

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'

我根本没有使用Sections,并将其设置为只有1个section:

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

当我点击UICollectionView区域时,它会发生(似乎是随机的)我有一段代码来从UICollectionView中删除元素:

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

这里是数组如何连接到 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;
    }
}
请帮我解决这个问题。我甚至不知道该如何捕获异常,因为它来自于UICollectionView的内部代码。 另外,我忘了提到我正在使用自定义布局的UICollectionView,但我不知道它是否与此问题有关。
谢谢大家的帮助!
编辑: 在调用所有布局方法后,我仍然会收到异常... 以下是我的自定义布局... 我仍然不确定如何修复它,因为我的所有尝试和捕获块都没能捕获到这个错误...
- (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]);
    }
}

你使用的主要viewController类是否实现了UICollectionViewDataSource协议?你是否将你的viewController(或其他)设置为UICollectionView的数据源? - Cashew
是的。它实现了2个协议:UICollectionViewDelegate和UICollectionViewDataSource。我已经将其设置为两个UICollectionView的数据源和代理。 - Josh Katz
6个回答

9

当我从手势识别器中运行reloadData时,出现了这种情况,设置手势识别器上的delaysTouchesBegan有所帮助。


6
这里的关键在于您的错误数字:
2147483647
这是NSNotFound的数值。在您的代码中,您可能正在对一个数组执行类似于indexOfObject:的操作,并将其结果作为部分或项索引之一传递给您的集合视图或布局方法之一,从而导致了此错误。虽然这并未发生在您问题中发布的代码中,但希望您现在能够找到它。

5
这对我有用:

这个方法适用于我:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.collectionView reloadData];
});

任何GUI的更改都需要从主线程触发。当您从块、延迟或手势识别器更改或刷新UICollectionView时,您需要将其调度到主队列上(如@Hampden123所述)。 - drpawelo

4

我刚刚遇到了这个断言。它的触发是因为我在触摸(滑动)事件中重新加载了集合数据。

最初的触摸(开始)触发了一个didHighlightItemAtIndexPath:消息,接下来集合数据通过滑动发生了变化,然后在触摸(抬起)时未能触发didUnhighlightItemAtIndexPath:消息。

由于我不需要高亮显示,解决方法是在我的控制器中实现这个方法:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    return NO;
}

我希望这能帮助到其他遇到同样问题的人。

1
我只想说,我遇到的问题是在长按触摸事件上重新加载集合数据。移除 reloadData 解决了我的问题。 - J.C.

3

不要在由手势识别器执行的方法中重新加载UICOllectionView的数据。完全遵循这个规则可以完美地解决这个问题。Daltsy建议在UICollectionView中禁用高亮显示也可以防止错误,但同时也会禁用所有的“didSelectItemAtIndexPath”代理消息。要小心,否则您可能会像我几分钟前那样得到一个几乎无用的UICollectionView。


0

与其禁用高亮,我发现在调用reloadData之前确保没有单元格被高亮显示可以避免“请求节前项目数”的错误。

UICollectionViewController.CollectionView.deselectItemAtIndexPath方法或Xamarin中的DeselectItem

我在模型数据中保存当前选定项的句柄,清除集合视图的高亮显示,为项目计算新的NSIndexPaths,然后调用reloadData。通过使用句柄通过可能的新NSIndexPath属性找到先前选择的项并再次选择它。

selectItemAtIndexPath:animated:scrollPosition:或Xamarin中的SelectItem


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接