无法在collectionView内调用dequeueReusableCellWithReuseIdentifier(collectionView:collectionViewLayout:sizeForItemAtIndexPath)

时间:2016-04-04 00:45:12

标签: ios swift uitableview uicollectionview uicollectionviewcell

dequeueReusableCellWithReuseIdentifier内调用collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize时,应用会崩溃。

注意:此问题不重复,因为dequeueReusableCellWithReuseIdentifier在UICollectionView的其他位置工作,而不是在特定函数中。

没有异常消息,Xcode只突出显示汇编代码,因此不确定问题所在。

代码如下。

目标是在宽度与UICollectionView的宽度匹配时使单元格高度动态,就像UITableView中的单元格一样。

1)为什么它会在dequeueReusableCellWithReuseIdentifier上崩溃?

2)如果你不能使用dequeueReusableCellWithReuseIdentifier,你怎么能动态地确定细胞的内在高度?

3)有没有更好的方法来模仿UITableViewCell的大小调整属性(即,与superview相同的宽度但动态高度)?关于这个主题有很多SO帖子,但没有提供非常干净的解决方案。

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(MessageCellIdentifier, forIndexPath: indexPath) as! MessageCell

    let cellSize = CGSize(width: view.frame.width, height: cell.frame.height)
    return cellSize
}

1 个答案:

答案 0 :(得分:1)

更接近理解崩溃

这是UITVC的1:1替代品,不会惹恼Apple。

首先,这是您的回调被使用的地方。

    // if delegate implements size delegate, query it for all items
    if (implementsSizeDelegate) {
        for (NSInteger item = 0; item < numberOfItems; item++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:(NSInteger)section];
            CGSize itemSize = implementsSizeDelegate ? [flowDataSource collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath] : self.itemSize;

            PSTGridLayoutItem *layoutItem = [layoutSection addItem];
            layoutItem.itemFrame = (CGRect){.size=itemSize};
        }

https://github.com/steipete/PSTCollectionView/blob/master/PSTCollectionView/PSTCollectionView.m

查看属性分配和最后一行 ...

- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath {
    // de-queue cell (if available)
    NSMutableArray *reusableCells = _cellReuseQueues[identifier];
    PSTCollectionViewCell *cell = [reusableCells lastObject];
    PSTCollectionViewLayoutAttributes *attributes = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath];

    // ... IMPL ...

    [cell applyLayoutAttributes:attributes];

    return cell;
}

需要经过很多代码,但至少有一条路径可以进入无限递归...

修改

从我在下面发布的链接...

  

由于之前调用了collectionView:layout:sizeForItemAtIndexPath:   cellForItemAtIndexPath:,所以我们需要初始化一个单元格并让它   系统使用自动布局为我们计算高度。为了避免记忆   泄漏,我们使用字典来缓存屏幕外的单元格(不是   显示在屏幕上)

在collectionView:layout:sizeForItemAtIndexPath:中,首先创建或检索一个单元格

var cell: MyCollectionViewCell? = self.offscreenCells[reuseIdentifier] as? MyCollectionViewCell
if cell == nil {
    cell = NSBundle.mainBundle().loadNibNamed("MyCollectionViewCell", owner: self, options: nil)[0] as? MyCollectionViewCell
    self.offscreenCells[reuseIdentifier] = cell
}

一旦单元格初始化,其大小由xib文件中的大小决定,因此,我们需要在单元格和layoutSubviews中配置文本,这将让系统重新计算单元格的大小

// Config cell and let system determine size
cell!.configCell(titleData[indexPath.item], content: contentData[indexPath.item], titleFont: fontArray[indexPath.item] as String, contentFont: fontArray[indexPath.item] as String)
// Cell's size is determined in nib file, need to set it's width (in this case), and inside, use this cell's width to set label's preferredMaxLayoutWidth, thus, height can be determined, this size will be returned for real cell initialization
cell!.bounds = CGRectMake(0, 0, targetWidth, cell!.bounds.height)
cell!.contentView.bounds = cell!.bounds

// Layout subviews, this will let labels on this cell to set preferredMaxLayoutWidth
cell!.setNeedsLayout()
cell!.layoutIfNeeded()
  

更新单元格后,调用var size =   细胞!.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)   获得这个单元格的大小。

     

在cellForItemAtIndexPath:中,单元格还需要配置并布局它   子视图

原稿

嗯,调用你命名的方法(它的一半)时它并没有崩溃,它在调用时崩溃

dequeueReusableCellWithReuseIdentifier(MessageCellIdentifier, 
    forIndexPath: indexPath) as! MessageCell

我看到的问题是你试图调用一个需要你调用它的方法的方法给你一个答案。它应该产生堆栈溢出。

我并不是说它不可能,但你不能压倒我认为的正确方法。

查看https://github.com/honghaoz/Dynamic-Collection-View-Cell-With-Auto-Layout-Demo/blob/master/README.md以获取您想要的示例,和/或发布更多代码。