iOS(Swift):集合视图indexPath(for:cell)对于非可见单元格为nil

时间:2018-06-07 14:52:17

标签: ios swift uicollectionview uicollectionviewcell

我有一个UIViewController,其中UICollectionView填充了Object类型的数组:

class MyViewController: UIViewController {

    let objects: [Object]!

    weak var collectionView: UICollectionView!

    func object(for cell: MyCell) {
        guard let indexPath = self.collectionView.indexPath(for: cell) else { fatalError("No cell at index path") }
    }

}

collectionView单元格由:

表示
class MyCell: UICollectionViewCell {

    weak var delegate: MyCellDelegate?

    override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
        super.apply(layoutAttributes)

        let obj = self.delegate?.object(for: self)
        // configure various subviews with obj ...

    }
}

delegateMyViewController对话,以获取代表的Object实例:

protocol MyCellDelegate: class {
    func object(for cell: MyCell) -> Object
}

当我在单元格之间向下滚动时,这样可以正常工作,但是当调用guard let indexPath = self.collectionView.indexPath(for: cell) ...方法时,对于屏幕外的单元格,它会在apply(_ layoutAttributes: UICollectionViewLayoutAttributes)处崩溃。

有没有办法解决这个问题?单元格需要知道它们所代表的Object个实例,以便视图控制器可以调整模型。

非常感谢您的帮助!

1 个答案:

答案 0 :(得分:4)

始终假设如果单元格在屏幕外,则集合视图已经回收了它。集合视图不断地执行此操作以保持较低的内存使用率和高性能。

要在屏幕外执行某些操作,我经常做的是在可见单元格可以附加的单独对象(MVVM中的视图模型)中。此对象由我的对象拥有和保留,永远不会被回收。如果我需要执行任何屏幕外操作,则此对象会执行此操作。

该单元的唯一工作是:

  1. 显示数据和
  2. 接收用户输入
  3. 这两个都要求它可见。

    当我创建单元格时,我使用prepareForReuse将其与上一个视图模型分离,并在将单元格附加到下一个单元格之前进行必要的清理。

    替代解决方案

    如果只需要获取特殊对象的索引路径,则只需使用布局属性中的索引路径即可。

    protocol MyCellDelegate: class {
        func object(for indexPath: IndexPath) -> Object
    }
    
    class MyCell: UICollectionViewCell {
    
        weak var delegate: MyCellDelegate?
    
        override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
            super.apply(layoutAttributes)
    
            let obj = self.delegate?.object(for: layoutAttributes.indexPath)
            // configure various subviews with obj ...
    
        }
    }