UICollectionView 在滚动时卡住

UICollectionView gets stuck while scrolling

我的 collectionView 单元格中有一些视频。我正在从 URL 中获取它们并使用 AVPlayer.

进行播放

一切正常。但是,根据视频是否包含音频,需要显示 mute/unmute 图标。

为了检查视频是否包含音频,我使用了以下代码:

(self.player?.currentItem?.asset.tracks.filter({[=10=].mediaType == AVMediaType.audio}).count != 0)

我从:How to check if AVPlayer has Video or just Audio?

添加此代码后,当我滚动集合视图时,我的 collectionView 第一次卡住了。

我从单元格的 init 调用它。 尝试在后台线程上执行它,但我仍然遇到问题。

DispatchQueue.global(qos: .background).async {
    let isAudioAvailable = (self.player?.currentItem?.asset.tracks.filter({[=11=].mediaType == AVMediaType.audio}).count != 0)
    DispatchQueue.main.async {
        self.audioIconButton.isHidden = !isAudioAvailable
        self.player?.isMuted = isMuted
        let image = isMuted ? #imageLiteral(resourceName: "Mute_Icon") : #imageLiteral(resourceName: "Unmute_Icon")
        self.audioIconButton.setImage(image, for: .normal)
    })
}

要从 URL 获取的代码:

func getAVPlayerFromUrl(view: UIView) -> AVPlayer? {
    let size: CGSize = view.bounds.size.applying(CGAffineTransform(scaleX: UIScreen.main.scale, y: UIScreen.main.scale))
    guard let url = URL(string: AppConfig.shared.appConfig.video_buckets.videoURL(for: self, size: size)) else { return nil }

    let videoAsset = AVURLAsset(url: url)
    videoAsset.loadValuesAsynchronously(forKeys: ["playable"])
    let playerItem: AVPlayerItem = AVPlayerItem(asset: videoAsset)
    return AVPlayer(playerItem: playerItem)
}

请让我知道这里出了什么问题。 或者有没有其他方法可以区分视频是否包含音频?

这里的想法是在加载 asset 时缓存计数,而不是加载 cell

因此获取逻辑将更改为类似于以下代码的内容

func getAVPlayerFromUrl(view: UIView, cellIndex: Int) -> AVPlayer? {
    let size: CGSize = view.bounds.size.applying(CGAffineTransform(scaleX: UIScreen.main.scale, y: UIScreen.main.scale))
    guard let url = URL(string: AppConfig.shared.appConfig.video_buckets.videoURL(for: self, size: size)) else { return nil }

    let videoAsset = AVURLAsset(url: url)
    videoAsset.loadValuesAsynchronously(forKeys: ["playable"]) {
        // Here audioCount is the dict we are using to save the count and cellIndex is the index of the cell in collectionview
        self.audioCount[cellIndex] = videoAsset.tracks.filter({[=10=].mediaType == AVMediaType.audio}).count
    }
    let playerItem: AVPlayerItem = AVPlayerItem(asset: videoAsset)
    return AVPlayer(playerItem: playerItem)
}

最后像

一样使用它
let isAudioAvailable = (self.audioCount[index] != 0)
self.audioIconButton.isHidden = !isAudioAvailable
self.player?.isMuted = isMuted
let image = isMuted ? #imageLiteral(resourceName: "Mute_Icon") : #imageLiteral(resourceName: "Unmute_Icon")
self.audioIconButton.setImage(image, for: .normal)