iOS (Swift): Collection View indexPath(for: cell) 对于非可见单元格为 nil

iOS (Swift): Collection View indexPath(for: cell) is nil for non visible cell

我有一个 UIViewController,它用 Object:

类型的数组填充 UICollectionView
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
}

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

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

非常感谢您的帮助!

总是假设如果一个单元格在屏幕外,那么集合视图已经回收了它。集合视图不断这样做以保持低内存使用率和高性能。

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

该单元的唯一工作是:

  1. 显示数据和
  2. 接收用户输入

两者都要求它可见。

当我创建单元格时,我使用 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 ...

    }
}