提问人:curiousProgrammer 提问时间:8/5/2021 最后编辑:curiousProgrammer 更新时间:8/23/2021 访问量:509
为什么引用集合视图中存在的项会返回 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
上面的代码位于一个函数中,该函数在视图控制器中按下按钮以在集合视图中显示新项时运行。在特定索引处添加新项目时,我不明白为什么会返回 nil 值。具体错误为“线程 1:致命错误:解包可选值时意外发现 nil”。只有当单元格在屏幕之外时,我才会收到此错误。这意味着,如果我在屏幕上的单元格很少时添加一个项目,或者如果我滚动到底部,如果有很多单元格并添加一个新项目,它将起作用。但是,如果有很多项目而我没有向下滚动,它就会出现该错误collectionView.insertItems(at: [indexPath])
let aCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell
答:
文档是这样说的:cellForItem(at:)
如果单元格不可见或 indexPath 超出范围,则此方法返回 nil
你得到一个值,因为你的单元格在屏幕之外,而强制投射导致崩溃。一般来说,你应该避免强制施放。nil
更新
我想您可能不熟悉表和集合视图的工作方式。它们不会为您拥有的每一行/项目存储一个单元格,而是创建一个单元格池并重复使用它们。
当单元格超出范围时,表/集合视图将停止将其与 IndexPath 关联,并且随着用户滚动,此旧单元格将再次用于需要显示的新 IndexPath。
通常,您应该完全在 中配置单元格,并且仅在应在其上显示的内容更改时用于更新可见单元格。collectionView(_:cellForItemAt:)
cellForItem(at:)
评论
有 2 种类似的方法。 实现方法,协议定义方法 他们做不同的事情。UICollectionView
cellForItem(at:)
UICollectionViewDataSource
collectionView(_:cellForItemAt:)
如果该单元格在屏幕上且未超出范围,则该方法将在指定的 IndexPath 处返回一个单元格。它用于获取当前可见的单元格。UICollectionView
cellForItem(at:)
如果在单节集合视图的前 5 个单元格可见时调用该方法,并请求第 6 个单元格的 indexPath,则将返回 nil。这就是代码中发生的情况。您正在尝试强制将 nil 转换为 ,因此您的代码崩溃了。别这样。检查你是否得到了一个零,并优雅地处理零。CollectionViewCell
如果向下滚动以使单元格 6 可见,然后请求单元格 6,则将返回该单元格。如果它当前处于屏幕外,它将返回 nil。正如@EmilioPelaez在他的回答(投票)中所说,这就是函数的工作原理。
另一种方法是集合视图调用的方法,以要求其数据源创建和配置单元格。该方法必须始终返回模型中任何有效 IndexPath 的单元格。但是,不应直接调用该方法。collectionView(_:cellForItemAt:)
评论
as!
CollectionViewCell
cellForItemAt
item
row