Swift如何提高UICollectionView获取照片缩略图显示效率

How to improve efficiency of getting thumbnails of photos and displaying them in UICollectionView in Swift

我正在 Swift 中编写一个简单的自定义照片选择器。看看 GIF,您会发现它有什么问题:

当我点击状态栏 quickly 滚动到顶部时,由于单元格被重复使用并且重新生成缩略图需要很短的时间,因此图片都混淆了,因此,这发生。我想知道无论我滚动多快,我如何解决这个问题?我的这个选择器代码是:

func getThumbnail(asset: PHAsset, targetSize: CGSize, onComplete: @escaping (UIImage?, [AnyHashable: Any]?) -> ()) {
    let manager = PHImageManager.default()
    let option = PHImageRequestOptions()
    option.resizeMode = .fast
    option.isNetworkAccessAllowed = true

    manager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: option) { (thumbnail, info) in
        onComplete(thumbnail, info)
    }
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = ...

    let asset = photos[indexPath.row]    // "photos" is an array of all photos in library
                                         // and its type is "[PHAsset]"

    let photoSize = collectionView.frame.width / 3
    getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
        (cell.viewWithTag(1) as! UIImageView).image = image
        // A cell has a UIImageView, whose size is equal to cell size,
        // whose tag = 1
    }))

    return cell
}

在你的 cellForItemAt 的第一行放

cell.imageView.image = 无

这将防止出列的单元重新使用图像,从而减少闪烁。如果图像在内存中,它会立即被替换,没问题。

仅仅因为您正在使用缓存并不意味着您所有的图像当前都在内存中。当您将图像读入内存时会发生闪烁,尤其是通过网络以及当您需要调整单元格大小时(尽管您的单元格看起来大小相同)。

您可能需要考虑在滚动结束时只更新一次视图,而不是针对每个单元格。

如果需要,您可以检查 scrollViewWillBeginDragging 以关闭更新和 scrollViewDidEndDecelerating 以执行更新。

我在 UITableView 中遇到了同样的问题。当我使用 AlamofireImage 时

af_setImage(withURL:  URL(string: pictureUrl))

然后我使用 AlamofireImage 的

af_setImage(withURL:  URL(string: pictureUrl)!, placeholderImage: UIImage(named: "YourPlaceholder.png")) 

使用占位符图像解决问题。

来自您的代码:

let cell = ...

此时,您还没有图像,因此您应该将图像视图的图像设置为 nil 或占位符图像:

let cell = ...
(cell.viewWithTag(1) as! UIImageView).image = placeholderImage

也来自您的代码:

getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
    (cell.viewWithTag(1) as! UIImageView).image = image

此时,cell 可能不再是原始索引路径(因此 image)的正确单元格。原始索引路径可能没有单元格,或者索引路径可能有不同的单元格。您需要向集合视图询问正确的单元格:

getThumbnail(asset: asset, targetSize: CGSize(width: photoSize, height: photoSize, onComplete: { (image, _) -> Void in
    guard let cell = collectionView.cellForItem(at: indexPath) else { return }
    (cell.viewWithTag(1) as! UIImageView).image = image