为什么引用集合视图 return 中存在的项目是 nil 值?

Why does referencing an item that exists in a collection view return a nil value?

let x = X(name: "x")
blocks.append(newBlock)
let indexPath = IndexPath(row: blocks.count - 1, section: 0)
collectionView.insertItems(at: [indexPath])
let aCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell

上面的代码是在视图控制器中按下按钮以在集合视图中显示新项目时运行的函数。由于 collectionView.insertItems(at: [indexPath]) 在特定索引处添加了一个新项目,我不明白为什么 let aCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell 会 return 一个 nil 值。具体的错误是“Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value”。当单元格在屏幕之外时,我只会收到此错误。这意味着如果我在屏幕上的单元格很少时添加一个项目,或者如果我在有很多单元格的情况下滚动到底部并添加一个新项目,它就会起作用。但是,如果有很多项目并且我没有向下滚动,则会出现错误

cellForItem(at:)documentation 是这样说的:

this method returns nil if the cell isn't visible or if indexPath is out of range

您得到的是 nil 值,因为您的单元格在屏幕之外,强制转换导致崩溃。一般来说,你应该避免强制施法。

更新

我想您可能不熟悉表和集合视图的工作方式。他们不会为您拥有的每个 row/item 存储一个单元格,而是创建一个单元格池并重复使用它们。

当单元格超出范围时,table/collection 视图停止将其与 IndexPath 相关联,并且随着用户滚动,这个旧单元格将再次用于需要显示的新 IndexPath。

一般来说,您应该在 collectionView(_:cellForItemAt:) 中完全配置您的单元格,并且仅在应显示在其上的内容更改时使用 cellForItem(at:) 更新可见单元格。

有2个类似的方法。 UICollectionView 实现方法 cellForItem(at:)UICollectionViewDataSource 协议定义方法 collectionView(_:cellForItemAt:) 它们做不同的事情。

UICollectionView 方法 cellForItem(at:) 将 return 指定 IndexPath 处的单元格,前提是它在屏幕上且未超出范围。它用于获取当前可见的单元格。

如果您在单节集合视图的前 5 个单元格可见时调用该方法,并请求第 6 个单元格的 indexPath,您将返回 nil。这就是您的代码中发生的事情。您正在尝试将 nil 强制转换为 CollectionViewCell,因此您的代码崩溃了。不要那样做。检查是否返回了 nil,并优雅地处理 nil。

如果您向下滚动以使单元格 6 可见,然后请求单元格 6,它将被 return 编辑。如果它当前不在屏幕上,它将 return nil。正如@EmilioPelaez 在他的回答(投票)中所说,这就是函数的工作原理。

另一种方法 collectionView(_:cellForItemAt:) 是集合视图调用的方法,要求其数据源创建和配置单元格。该方法必须始终 return 模型中任何有效 IndexPath 的单元格。不过,您不应该直接调用该方法。