17

试图将补充视图添加到我UICollectionView的标题中。我在让它工作时遇到问题。

我使用自定义UICollectionViewFlowLayout返回一个contentSize始终比框架大至少 1 像素的 a (我使用的 aUIFreshControl只有在UICollectionView滚动时才有效,并且collectionView.contentSize直接设置什么都不做)并invalidateLayout打开sectionInsertitemSize更改:

-(void)setSectionInset:(UIEdgeInsets)sectionInset {
    if (UIEdgeInsetsEqualToEdgeInsets(super.sectionInset, sectionInset)) {
        return;
    }

    super.sectionInset = sectionInset;

    [self invalidateLayout];

}

-(void) setItemSize:(CGSize)itemSize {
    if (CGSizeEqualToSize(super.itemSize, itemSize)) {
        return;
    }

    super.itemSize = itemSize;

    [self invalidateLayout];
}

- (CGSize)collectionViewContentSize
{
    CGFloat height = [super collectionViewContentSize].height;

    // Always returns a contentSize larger then frame so it can scroll and UIRefreshControl will work
    if (height < self.collectionView.bounds.size.height) {
        height = self.collectionView.bounds.size.height + 1;
    }

    return CGSizeMake([super collectionViewContentSize].width, height);
}

我创建了一个UICollectionReusableView只有 aUIView的类UILabel

@implementation CollectionHeaderView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"CollectionHeaderView" owner:self options:nil];

        if ([arrayOfViews count] < 1) {
            return nil;
        }

        if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
            return nil;
        }

        self = [arrayOfViews objectAtIndex:0];

        self.headerLabel.text = @"This is a header. There are many like it.";
        self.backgroundColor = [UIColor yellowColor];


    }
    return self;
}

试图实现它:

DatasetLayout *collectionViewFlowLayout = [[DatasetLayout alloc] init];
collectionViewFlowLayout.itemSize = CGSizeMake(360, 160);
collectionViewFlowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
collectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16);
collectionViewFlowLayout.minimumInteritemSpacing = 16;
collectionViewFlowLayout.minimumLineSpacing = 16;
collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100);

UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewFlowLayout];
collectionView.translatesAutoresizingMaskIntoConstraints = FALSE;
collectionView.backgroundColor = [UIColor yellowColor];
collectionView.delegate = self;
collectionView.dataSource = self;

我注册课程:

[self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

并实现委托:

-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {

    CollectionHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView" forIndexPath:indexPath];

    headerView.headerLabel.text = @"Blarg!";

    return headerView;
}

线

collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100);

导致错误:

*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:], /SourceCache/UIKit_Sim/UIKit-2380.17/UICollectionView.m:1150
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'

如果我将其注释掉,它会运行但没有标题。

我做错了什么或没有实施?

4

10 回答 10

13

我遇到了类似的问题,但是在我以编程方式弹出 UICollectionViewController 后,我的应用程序崩溃了。出于某种原因(我认为这只是 SDK 中的一个错误)self.collectionView 在其控制器销毁后仍然存在,从而导致此故障:

*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-2935.137/UICollectionView.m:1305
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'

解决方案只是覆盖 UICollectionViewController 中的 -dealloc 并手动释放 self.collectionView。弧码:

- (void)dealloc {

    self.collectionView = nil;
}

希望这会为某人节省时间。

于 2014-04-26T12:51:08.677 回答
10

这个主题的答案很老了,在 iOS8 和 iOS9 中不起作用。如果您仍然遇到所描述的问题,请查看以下主题:UICollectionView and Supplementary View crash

编辑

这是答案,以防链接失效:

如果您在集合视图中使用自定义布局,请检查其数据源是否为 nil:

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

结果应如下所示:

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    if (self.collectionView.dataSource != nil) {
        // Your layout code    
        return array;
    }
    return nil;
}

此更改解决了以下问题:

  • -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:] 中的断言失败

您还可以检查以下主题,但在我的情况下它没有解决任何问题:

如果部分标题隐藏在 UICollectionView 中,则删除空白区域

希望它会帮助你,你不会像我那样浪费太多时间。

于 2015-09-28T12:31:18.247 回答
7

我清理了我的代码并删除了我在 IB 中创建的 UICollectionView 并在代码中创建了它。我再次运行它并得到一个不同的错误,并意识到我没有在 IB 中设置委托或数据源。我做了:

self.collectionView.delegate = self;
self.collectionView.datasource = self;

但这一定还不够好。

因此,在 IB 中创建 UICollectionView 而不是在 IB 中设置 delgate/数据源,而是在代码中:

[self.view bringSubviewToFront:self.collectionView];
self.collectionView.collectionViewLayout = collectionViewFlowLayout;
self.collectionView.backgroundColor = [UIColor orangeColor];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;

[self.collectionView registerClass:[DatasetCell class] forCellWithReuseIdentifier:@"cvCell"];

[self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

是一个问题。我重做了它以在代码中创建 UICollectionView:

UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewFlowLayout];
collectionView.translatesAutoresizingMaskIntoConstraints = FALSE;
collectionView.backgroundColor = [UIColor yellowColor];
collectionView.delegate = self;
collectionView.dataSource = self;

[collectionView registerClass:[DatasetCell class] forCellWithReuseIdentifier:@"cvCell"];

[collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

[self.view addSubview:collectionView];

self.collectionView = collectionView;

我得到一个不同的错误:

*** Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2380.17/UICollectionView.m:2249
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindSectionHeader with identifier CollectionHeaderView - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

我会试着弄清楚。

编辑:

想通了,我错误地注册了标题:

[collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

切换到:

UINib *headerNib = [UINib nibWithNibName:@"CollectionHeaderView" bundle:nil];

[collectionView registerNib:headerNib forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

一切正常。不完全确定它registerClass:是如何不起作用的。

于 2013-03-05T18:06:03.270 回答
1

如果您查看错误消息,它表示未设置数据源。这应该解决它:

self.collectionView.dataSource = self;

确保您的视图控制器实现数据源协议:

YourViewController : UIViewController<UICollectionViewDataSource>

于 2013-03-05T17:50:11.423 回答
1

我也遇到了这个烦人的错误:

*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-3347.44/UICollectionView.m:1400
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'

我发现有些人通过这样做来解决这个错误

- (void)dealloc {
    self.collectionView = nil;
}

或迅速:

deinit {
    collectionView = nil
}

但是这些都没有解决我的崩溃。我尝试了一些方法,下面的“hack”解决了这个烦人的错误:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    if collectionView.dataSource != nil {
        return someHeaderSize
    } else {
        return CGSizeZero
    }
}
于 2015-05-28T14:51:55.910 回答
1

此答案类似于您创建检查数据源的方法的其他答案,但它更简单一些。似乎这个问题与集合发布后集合视图的布局有关。所以我将布局的属性归零,如下所示,错误消失了。

deinit {
    let layout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    layout.estimatedItemSize = CGSizeZero
    layout.sectionInset = UIEdgeInsetsZero
    layout.headerReferenceSize = CGSizeZero
}
于 2015-11-10T02:00:13.237 回答
0

我遇到了同样的问题,同样,我没有正确注册标题。这里有几个线程都建议使用 Nib 来定义标题,但我做了不同的事情并且工作正常。

我有一个自定义标头 SizeCollectionHeader,它继承了 UICollectionReusableView。它是这样注册的。

    [self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"UICollectionElementKindSectionHeader"
                                                                             withReuseIdentifier:@"SupplementaryViewIdentifier"];

并且工作正常。

我最初的问题是有一个像这样的随机“Kind”值。

    [self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"SupplementaryViewKind"
                                                                             withReuseIdentifier:@"SupplementaryViewIdentifier"];

这会崩溃。

所以我只是想为任何在这里寻找你不需要使用笔尖的人发表评论。

于 2015-06-24T14:56:11.420 回答
0

尝试这个 :

self.collectionView?.dataSource = nil
self.collectionView = nil

它对我有用;)

于 2015-10-08T13:20:15.053 回答
0

我一直收到同样的错误。我已经为我的 collectionView 设置了 CustomHeaderView。我将 Collection Reusable View 类放到了我的 CustomHeaderView 中,并且我已经设置了标识符。我花了 1/2 小时试图找出失败的原因。

由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无法使一种视图出列:带有标识符 SectionHeader 的 UICollectionElementKindSectionFooter - 必须为标识符注册一个 nib 或一个类或连接故事板中的原型单元格”

您需要仔细阅读日志......吸取的教训。

'不能出列同类视图:UICollectionElementKindSectionFooter

原因是因为在故事板中 - 在 collectionView 身份检查器中,我检查了两个附件:部分页眉和部分页脚。我只需要节标题。只需取消选中页脚...构建并运行..BOOM!

于 2016-01-02T20:34:46.017 回答
0

一个 iOS9 的 bug,在 viewcontroller 的 dealloc 中设置层委托 nil。

- (void)dealloc{

    if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"9"]) {
        self.collectionView.layer.delegate = nil;
    }
}
于 2016-09-27T07:18:55.503 回答