UICollectionView cellForItem(at:) 崩溃
Posted
技术标签:
【中文标题】UICollectionView cellForItem(at:) 崩溃【英文标题】:UICollectionView cellForItem(at:) crashes 【发布时间】:2018-01-25 10:20:21 【问题描述】:我正在使用 Swift4 和 Xcode9。
我使用下面的委托方法创建了我的 collectionView 单元格;
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mediaItemCell", for: indexPath) as! MediaItemCollectionViewCell
cell.mediaItemCellImageView.image = mediaPlayer?.item(at: indexPath.row)?.image
return cell
然后,我想用“停止”图像替换所选单元格的图像。为此,我尝试使用didSelectItemAt
方法;
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
if (mediaPlayer?.isPlaying == true)
// stop the player
mediaPlayer?.stopPlayingMedia()
else
// change the image and start playing
let cell = collectionView.cellForItem(at: indexPath) as! MediaItemCollectionViewCell // CRASH
cell.mediaItemCellImageView.image = UIImage(named: "stop.png")
...
...
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath)
// restore the original image
let cell = collectionView.cellForItem(at: indexPath) as! MediaItemCollectionViewCell
cell.mediaItemCellImageView.image = mediaPlayer?.item(at: indexPath.row)?.image
// stop playing
mediaPlayer?.stopPlayingMedia()
现在,当我选择已选择的单元格(因此原始图像已被“stop.png”替换)时,上面的代码有效;即恢复原图,通过stopPlayingMedia()
方法完成。
当我选择与当前选择的单元格不同的单元格时,应用程序崩溃。我试图将didSelectItemAt
调用移出委托方法,但没有成功。
令人惊讶的是,当我选择当前选定的单元格时,逻辑检查if collectionView.cellForItem(at: indexPath) is MediaItemCollectionViewCell
成功,而当我选择另一个单元格时失败。
我想更改单元格的图像,因此需要转换变量类型但它失败了。为什么当我选择与当前选择的单元格不同的单元格时,投射失败?
谢谢
编辑:
我使用 collectionView.reloadData()
将所有图像恢复为原始图像(我在 OP 中提到了这一点 - 当调用 stopPlayingMedia()
时)。看来,如果我将private var index:IndexItem?
添加到我的ViewController
类并在didSelectItemAt
中更新其值(以保存最后选择的单元格)并使用下面的代码,则代码不会崩溃
extension ViewController:MediaPlayerControllerDelegate
// this delegate method is invoked when stopPlayingMedia() is called
func mediaPlayerControllerDidFinishPlaying()
// restore the UI
// collectionView.reloadData() -> this causes the crash, instead, I only restore one cell
let cell = collectionView.cellForItem(at: index!) as! MediaItemCollectionViewCell
cell.mediaItemCellImageView.image = mediaPlayer?.item(at: (index?.row)!)?.image
timeLabel.text = "00:00"
progressBar.progress = 0.0
【问题讨论】:
它崩溃了?什么是崩溃日志?如果单元格不可见,cellForItem(at:)
也会返回 nil,所以很明显,在它之后执行 as!
并不是一个好主意,您应该执行 if let
insetad。
您收到什么错误信息?
我收到Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
错误。为什么我选择同一个单元格时强制转换成功但选择另一个单元格时失败?
"为什么当我选择同一个单元格时强制转换成功,但在选择另一个单元格时失败?"因为如果单元格不可见。当它崩溃时,单元格是否可见?我不这么认为。
@Larme, print(collectionView.visibleCells.count)
当我选择当前选定的单元格时给出 12,当我选择另一个单元格时给出 0。我想我需要先澄清“可见细胞”的概念!任何解释将不胜感激!
【参考方案1】:
我尝试了以下方法来创建单元格并在选择时更改单元格内的图像。一点也不崩溃。请检查实现,它可能会帮助你。
import UIKit
class ViewController: UIViewController
private var isPlayingModel = [false, false, false, false, false] // initially all are stop, not playing
@IBOutlet weak var collectionView: UICollectionView!
didSet
collectionView.delegate = self
collectionView.dataSource = self
extension ViewController: UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int
return 1
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return isPlayingModel.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mediaItemCell", for: indexPath) as! MediaItemCollectionViewCell
cell.imageVw.image = isPlayingModel[indexPath.row] ? #imageLiteral(resourceName: "start") : #imageLiteral(resourceName: "stop")
return cell
extension ViewController: UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
isPlayingModel[indexPath.row] = !isPlayingModel[indexPath.row]
let cell = collectionView.cellForItem(at: indexPath) as! MediaItemCollectionViewCell
cell.imageVw.image = isPlayingModel[indexPath.row] ? #imageLiteral(resourceName: "start") : #imageLiteral(resourceName: "stop")
extension ViewController: UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
return CGSize(width: view.frame.size.width, height: 60)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
return 4
class MediaItemCollectionViewCell: UICollectionViewCell
@IBOutlet weak var imageVw: UIImageView!
Check the implementation here.
【讨论】:
【参考方案2】:您没有正确传递 indexPath 来加载单元格,这就是它崩溃的原因。编辑您的 didSelectItemAt:
方法如下:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
let selectedCell = IndexPath(item: indexPath.item, section: indexPath.section)
let cell = collectionView.cellForItem(at: selectedCell) as! ACollectionViewCell
cell.imgView.image = UIImage(named: "3.jpg")
【讨论】:
【参考方案3】:集合视图 indexPath 具有元素 item
,而不是 row
试试这个看看:(让我知道它打印了什么)
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath)
// restore the original image
if let cell = collectionView.cellForItem(at: indexPath) as? MediaItemCollectionViewCell
if let cellImage = mediaPlayer?.item(at: indexPath.item)?.image // Collection view indexPath has element `item`, and not `row`
cell.mediaItemCellImageView.image = cellImage
else
print("cellImage not found at indexPath - \(indexPath)")
else
print("collection view cell `MediaItemCollectionViewCell` not found at indexPath -\(indexPath) ")
// stop playing
mediaPlayer?.stopPlayingMedia()
【讨论】:
代码根本不打印任何东西,其实didDeselectItemAt
方法就可以了。
那么问题出在哪里,如果它没有打印任何 else
块语句,那么我认为它应该可以正常工作,没有应用程序崩溃,对吧?您对此还有其他问题吗?以上是关于UICollectionView cellForItem(at:) 崩溃的主要内容,如果未能解决你的问题,请参考以下文章
如何滚动另一个 UICollectionView 下方的 UICollectionView?
UICollectionView 单元内部已加载,但 UICollectionView 未显示
UICollectionView 断言失败 -[UICollectionView _updateWithItems:tentativelyForReordering:]
UITableviewCell 中的 UICollectionView。添加约束后,UICollectionView 不显示