为什么didDeselectItemAt的UICollectionView抛出一个意外的错误发现nil并崩溃应用程序Swift?

Cas*_*ert 5 ios swift

我使用了一个集合视图来显示一组图像.它正在工作,但是当我使用该功能时didDeselectItemAt,如果我点击某些图像,它将崩溃.

发生错误: fatal error: unexpectedly found nil while unwrapping an Optional value

代码设置:

numberOfItemsInSection:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return images.count
}
Run Code Online (Sandbox Code Playgroud)

cellForItemAt:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cellIdentifier = "ImageCell"
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! ImageCollectionViewCell

        let imageUrls = collection?.imageUrls

        // Configure the cell
        // Reset alpha of first item in collection
        if indexPath.row == 0 {
            cell.imageView.alpha = 1.0

            if videoUrl != nil {
                cell.backgroundColor = UIColor.red
                cell.imageView.alpha = 0.5
            }
        }
        cell.imageView.af_setImage(withURL: URL(string: (imageUrls?[indexPath.row])!)!)

        return cell
    }
Run Code Online (Sandbox Code Playgroud)

didDeselectItemAt:

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        let cell = collectionView.cellForItem(at: indexPath) as! ImageCollectionViewCell

        UIView.animate(withDuration: 0.3, animations: {
            cell.imageView.alpha = 0.6
        })
    }
Run Code Online (Sandbox Code Playgroud)

didSelectItemAt:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        print("You've tapped me. NICE!! \(indexPath.row)")

        let cell = collectionView.cellForItem(at: indexPath) as! ImageCollectionViewCell

        cell.imageView.alpha = 1

        let url = self.collection?.imageUrls?[indexPath.row]
        self.selectedImageUrl = url

        Alamofire.request(url!).responseImage(completionHandler: {
            (response) in
            if response.result.value != nil {
                self.selectedImage.image = response.result.value
            }
        })

    }
Run Code Online (Sandbox Code Playgroud)

上面的代码工作正常,但如果我点击某些图像会抛出错误.每个集合视图的第一个单元格的alpha值为100% - 1.0,其他所有的单元格的alpha值为0.6.我注意到的是 - 除了集合视图的第一个单元格 - 每个第7个单元格也有100%的alpha,如果集合视图包含videoUrl,它将具有红色背景和50%的alpha.

这是因为可重用的单元格,如UITableViewController,您在哪里使用,并且您是否dequeueReusableCell应该使用该功能didDeselectItemAt或其他未正确实现的东西?

因此,只有集合视图中的第一个单元格的alpha值为100,其他60%的单元格.如果对象具有videoUrl,则第一个元素的alpha为50%,背景为红色.

如果还有任何问题,请告诉我.在此先感谢,祝大家愉快!

更新:

单击集合视图的第一个图像,然后单击第二个图像时,下面的打印行将输出到代码下方.这不会使应用程序崩溃,它仍然有效

print("OUTPUT \(String(describing: collectionView.cellForItem(at: indexPath)))")
Run Code Online (Sandbox Code Playgroud)

上面的代码片段我放在两个didSelectItemAtdidDeselectItemAt:

didSelectItemAt输出:

OUTPUT Optional(<CollectionViewApp.ImageCollectionViewCell: 0x7ff61679c1a0; baseClass = UICollectionViewCell; frame = (150 0; 150 100); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x6080000347c0>>)
Run Code Online (Sandbox Code Playgroud)

didDeselectItemAt输出:

OUTPUT可选(>)

当我单击第一个或第二个图像,然后单击集合视图中的最后一个图像时,将发生错误并将使我的应用程序崩溃.第一张图片上的触摸会给我输出:

OUTPUT Optional(<CollectionViewApp.ImageCollectionViewCell: 0x7fc3cb038540; baseClass = UICollectionViewCell; frame = (150 0; 150 100); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x610000225980>>)

最后一项 - 让我的应用程序崩溃 - 将抛出以下输出: OUTPUT Optional(<CollectionViewApp.ImageCollectionViewCell: 0x7fc3cb03afb0; baseClass = UICollectionViewCell; frame = (300 0; 150 100); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x6100002264c0>>).

因此,当您在第一个图像超出画布时单击集合视图中的第一个图像之后以及集合视图中的最后一个图像之后,可以触发崩溃.我使用了水平集合视图.

mar*_*aie 6

因此崩溃正在发生,因为在选择项目时,didDeselectItemAt可以调用不再可见的项目.在UICollectionView重新使用UICollectionViewCells,这意味着该collectionView.cellForItem(at: indexPath)方法将返回零为不可见的细胞.要解决此问题,您可以使用以下代码:

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    guard let cell = collectionView.cellForItem(at: indexPath) as! ImageCollectionViewCell else {
        return //the cell is not visible
    }

    UIView.animate(withDuration: 0.3, animations: {
        cell.imageView.alpha = 0.6
    })
}
Run Code Online (Sandbox Code Playgroud)

我有一些改进代码的建议:

你有很多地方可以展开你的价值观.

考虑采用以下方法:

guard let url = self.collection?.imageUrls?[indexPath.row] else {
    fatalError("url was nil")
}

self.selectedImageUrl = url

Alamofire.request(url).responseImage(completionHandler: {
    (response) in
    if response.result.value != nil {
        self.selectedImage.image = response.result.value
    }
})
Run Code Online (Sandbox Code Playgroud)

通过使用guard语句,您可以使用相应的错误消息强制应用程序崩溃,这将在调试时帮助您.与强行展开相比,这是一种更好的做法.

此外,当出列单元格时,您可以选择以下内容:

let cellIdentifier = "ImageCell"
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as? ImageCollectionViewCell else  {
    fatalError("Wrong cell type")
}
Run Code Online (Sandbox Code Playgroud)

当细胞类型不同时,可能会发生这种情况