【问题标题】:Assertion failure in -[UICollectionViewData numberOfItemsBeforeSection:]-[UICollectionViewData numberOfItemsBeforeSection:] 中的断言失败
【发布时间】:2012-10-14 01:06:47
【问题描述】:

使用 IOS 6 和新的 UICollectionView 我在 UIViewController 上有 2 个 UICollectionViews 并使用 Storyboard 单击 UICollectionView 时出现以下错误 我不确定为什么会发生这种情况,Google 会针对此错误返回 0 个结果...

2012-10-13 20:30:06.421 MyApp[768:907] 断言失败 -[UICollectionViewData numberOfItemsBeforeSection:], /SourceCache/UIKit/UIKit-2372/UICollectionViewData.m:415
2012-10-13 20:30:06.427 MyApp [768:907] 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“当集合视图中只有 1 个部分时,请求第 2147483647 部分之前的项目数”

我根本不使用 Sections 并将其设置为仅 1 个部分:

- (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 使用自定义布局,但我不知道它是否与这个问题有关。

再次感谢你们的帮助!

编辑: 在调用所有布局方法后,我得到了异常...... 这是我的自定义布局... 我仍然不确定如何修复它,因为我所有的 try catch 块都没有捕获错误...

- (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 的数据源?
  • 是的。它实现了 2 个协议:UICollectionViewDelegate 和 UICollectionViewDataSource。我已将其设置为数据源以及其上 2 个 UICollectionViews 的委托。

标签: iphone ios ios6 iphone-developer-program uicollectionview


【解决方案1】:

我在从手势识别器运行 reloadData 时发生了这种情况,在手势识别器上设置 delaysTouchesBegan 有帮助。

【讨论】:

    【解决方案2】:

    这里的关键是您的错误中的这个数字:

    2147483647

    这是NSNotFound 的数值。在代码中的某处,您正在对数组执行类似indexOfObject: 的操作,并将其结果作为节或项索引传递到您的集合视图或布局方法之一,这会导致错误。您问题中发布的代码中没有发生这种情况,但希望您现在能够找到它。

    【讨论】:

      【解决方案3】:

      这对我有用:

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

      【讨论】:

      • 对 GUI 的任何更改都需要从主线程触发。当从块、延迟或手势识别器更改或刷新 UICollectionView 时,您需要在主队列上调度它(如上面@Hampden123 所述)。
      【解决方案4】:

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

      第一次触摸(开始)触发didHighlightItemAtIndexPath:消息,然后收集数据发生变化(通过滑动),然后在触摸(提升)时未能触发didUnhighlightItemAtIndexPath:消息。

      由于我不需要突出显示,因此解决方案是在我的控制器中实现此方法:

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

      我希望这可以帮助其他遇到此问题的人。

      【讨论】:

      • 我只想说,我遇到的问题是在长按触摸事件时重新加载集合数据。删除 reloadData 解决了我的问题。
      【解决方案5】:

      永远不要在手势识别器执行的方法上重新加载 UICollectionView 的数据。遵循这个规则完全解决了这个问题。 Daltsy 建议在 UICollectionView 中停用高亮显示也可以防止错误,但也会停用所有“didSelectItemAtIndexPath”委托消息。请小心,因为您可能会得到一个几乎没用的 UICollectionView - 就像我几分钟前所做的那样。

      【讨论】:

        【解决方案6】:

        我发现在调用 reloadData 之前确保没有单元格被突出显示可以防止“请求节前的项目数”错误,而不是禁用突出显示。这是

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

        我在模型数据中保存当前选中项的句柄,清除集合视图的突出显示,为这些项计算新的 NSIndexPaths,然后调用 reloadData。使用句柄通过其可能的新 NSIndexPath 属性再次选择之前选择的项目。

        selectItemAtIndexPath:animated:scrollPosition: 或 SelectItem 在 Xamarin 中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-26
          • 1970-01-01
          • 2011-05-27
          • 2017-08-07
          • 2012-08-01
          • 2015-09-01
          相关资源
          最近更新 更多