UICollectionView cellForItem(at :)崩溃

时间:2018-01-25 10:20:21

标签: ios swift uicollectionview uicollectionviewcell swift4

我正在使用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
    }
}

3 个答案:

答案 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!
 }

Output

Check the implementation here.

答案 1 :(得分:0)

您没有正确传递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")
     }

答案 2 :(得分:0)

集合视图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()
}