为什么引用集合视图中存在的项会返回 nil 值?

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

提问人:curiousProgrammer 提问时间:8/5/2021 最后编辑:curiousProgrammer 更新时间:8/23/2021 访问量:509

问:

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

iOS Swift null UIColictionView

评论

1赞 aheze 8/5/2021
也许是失败了。你确定这个单元格是一个吗?as!CollectionViewCell
0赞 curiousProgrammer 8/5/2021
对不起,我忘了提到只有当单元格在屏幕外时才会收到此错误。这意味着,如果我在屏幕上的单元格很少时添加一个项目,或者如果我滚动到底部,如果有很多单元格并添加一个新项目,它将起作用。但是,如果有很多项目而我没有向下滚动,它就会出现该错误。
0赞 Paulw11 8/5/2021
为什么需要刚刚插入的项的单元格?您应该执行配置新单元所需的任何操作cellForItemAt
0赞 Paulw11 8/5/2021
此外,您的代码将起作用,但您应该使用 ,而不是在处理集合视图时使用itemrow
0赞 curiousProgrammer 8/5/2021
我意识到我可能做错了,但我想要刚刚插入的项的单元格,因为我想使单元格上的标签等于对象的值。因此,第一项的标签将等于数组中第一个对象的值之一,依此类推。

答:

2赞 EmilioPelaez 8/5/2021 #1

文档是这样说的:cellForItem(at:)

如果单元格不可见或 indexPath 超出范围,则此方法返回 nil

你得到一个值,因为你的单元格在屏幕之外,而强制投射导致崩溃。一般来说,你应该避免强制施放。nil

更新

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

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

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

评论

0赞 curiousProgrammer 8/5/2021
如果我想访问刚刚创建的项目,即使它不可见,我该怎么办?
0赞 EmilioPelaez 8/5/2021
这取决于您要对单元执行的操作,但如果要对其进行配置,则应在集合视图请求新单元时进行配置。
0赞 curiousProgrammer 8/5/2021
我相信我做错了,但我想要的是让集合视图中的每个项目显示(使用标签)数组中相应对象的值。这意味着第一项将有一个标签,表示数组中第一个对象的值之一,依此类推。这就是为什么当我添加一个对象时,我希望它的标签等于数组中对象的值。
1赞 Duncan C 8/5/2021 #2

有 2 种类似的方法。 实现方法,协议定义方法 他们做不同的事情。UICollectionViewcellForItem(at:)UICollectionViewDataSourcecollectionView(_:cellForItemAt:)

如果该单元格在屏幕上且未超出范围,则该方法将在指定的 IndexPath 处返回一个单元格。它用于获取当前可见的单元格。UICollectionViewcellForItem(at:)

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

如果向下滚动以使单元格 6 可见,然后请求单元格 6,则将返回该单元格。如果它当前处于屏幕外,它将返回 nil。正如@EmilioPelaez在他的回答(投票)中所说,这就是函数的工作原理。

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