*** Assertion failure in -[ShopInfoCollectionView _dequeueReusableViewOfKind:withIdentifier:forIn...

  • iPhone系统
    iOS 9.2 iOS 9.3.5 (12.0系统未出现崩溃)
  • 布局情况
    一个collectionView中有5个section,第一个section的header与其余的header不同,并且只有最后一个section有footer,其他section没有footer。
  • 崩溃操作
    当后台返回数据中,只给出了一个section的数据,其余四个section没有数据。即:只显示第一个section的header和items。
    此时发生崩溃,崩溃在返回header 和 footer的数据源方法处,报出断言失败 。
    *** Assertion failure in -[ShopInfoCollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:]
    或者
    *** Assertion failure in -[UICollectionViewData layoutAttributesForSupplementaryElementOfKind:atIndexPath:]
  • 代码书写
// 初始化方法中注册 item header footer
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout*)layout
{
    self = [super initWithFrame:frame collectionViewLayout:layout];
    if(self) {
        [self registerClass:[CollectionCell class] forCellWithReuseIdentifier:@"cell"];
        [self registerClass:[CollectionHeader_1 class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeader_1"];
       [self registerClass:[CollectionHeader_2 class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeader_2"];
        [self registerClass:[CollectionFooter class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionFooter"];
    }
    return self;
}

// 返回item的size
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath{
       return CGSizeMake((375 - 30)*0.5, (375 - 30)*0.5*1.5);
}

// 返回header的size
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{
    if(section ==0){
        return CGSizeMake(375, 100);
    }else{
            return CGSizeMake(375, 70);
        }
  }

// 返回footer的size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section{
    if (section == _sourceArr.count - 1){
        return CGSizeMake(375, 50);
}else{
        return CGSizeZero;
    }
}

// 返回 item
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        CollectionCell *item = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
        return item;
}

// 返回header 和 footer
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
    
    if (indexPath.section == 0){
// *****************崩溃在这个位置*********************
        CollectionHeader_1 *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeader_1" forIndexPath:indexPath];

        return header;
    }else if (indexPath.section == _sourceArr.count - 1){
        if (kind == UICollectionElementKindSectionHeader){
            CollectionHeader_2 *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeader_2" forIndexPath:indexPath];
            return header;
        }else{
            CollectionFooter *footer = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionFooter" forIndexPath:indexPath];
            return footer;
        }
    }else{
        CollectionHeader_2 *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeader_2" forIndexPath:indexPath];
        return header;
    }
}

  • 原因分析
    在崩溃处,打印方法返回的kind值发现是:UICollectionElementKindSectionFooter ,但是上面代码中进入section==0的分支中并没有给出footer的类,所以报出断言失败。
    业务中第一个section不需要footer,所以一开始就没有给出第一个section的footer。但是在返回footer高度时,为section == 0的footer,设置了CGSizeZero。因为有了footer的size所以collectionView会去找一个secction的footer,很遗憾它没有找到,然后就崩了!!!
  • 解决方案
    修改 返回header 和 footer 方法中的代码逻辑,首先判断kind,确定初始化header还是footer,然后再根据不同的section返回不同的header、footer对象,具体如下:
// 返回header 和 footer
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
    if (kind == UICollectionElementKindSectionHeader){
     if (indexPath.section == 0){
        CollectionHeader_1 *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeader_1" forIndexPath:indexPath];

        return header;
    }else{
        CollectionHeader_2 *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeader_2" forIndexPath:indexPath];
        return header;
    }
}else{
    CollectionFooter *footer = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionFooter" forIndexPath:indexPath];
    return footer;
}   
}
  • 疑问?
    目前原来的代码在iOS 12.0的系统上运行平稳,没有出现崩溃,而在iOS 9.x系统中崩溃必现,还不了解为什么?如果有人知道,请告知谢谢。

你可能感兴趣的:(*** Assertion failure in -[ShopInfoCollectionView _dequeueReusableViewOfKind:withIdentifier:forIn...)