You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UITableView使用AVPlayer播放Firebase音频错误及滚动停止如何解决?

问题成因
  • 全局唯一的AVPlayer实例被无规律覆盖:你在cellForRowAt单元格渲染回调中直接调用异步的loadAudio方法,每次音频下载URL请求返回后都会直接替换全局的audioPlayer,由于异步请求返回顺序不固定,最终audioPlayer绑定的音频完全不可控,点击播放时就会出现随机播放的问题。
  • 滚动时播放中断是单元格复用机制导致的:UITableView滚动过程中,新进入可视区域的单元格会触发cellForRowAt回调,重复调用loadAudio,请求返回后会直接替换正在播放的AVPlayer实例,原有播放器被释放自然就停止播放。
  • 播放逻辑未绑定目标音频:playMusic方法传入的索引参数未被使用,没有根据点击的单元格索引加载对应音频,直接调用当前audioPlayer的播放方法,也没有切歌的逻辑处理,自然无法实现点击其他单元格自动切换歌曲的效果。
修复方案

1. 新增全局状态管理

新增两个变量用于缓存音频URL和记录当前播放状态,避免重复请求和播放错乱:

// 缓存已获取的音频URL,key用post的mp3唯一标识即可
var audioUrlCache: [String: URL] = [:]
// 记录当前正在播放的音频唯一标识
var currentPlayingAudioKey: String?

2. 移除cellForRowAt中的预加载逻辑

绝对不要在单元格渲染方法中执行异步修改全局播放器的操作,把loadAudio的调用时机改到用户点击播放按钮时触发,避免无意义的请求和播放器被意外覆盖。

3. 重写播放逻辑,增加切歌处理

修改playMusic方法,实现点击判断、切歌、缓存复用的逻辑:

func playMusic(index: Int) {
    let targetPost = compPosts[index]
    let targetKey = targetPost.mp3
    
    // 点击的是当前正在播放的音频,直接操作播放状态即可
    if currentPlayingAudioKey == targetKey {
        if !isPlaying {
            audioPlayer.play()
            isPlaying = true
        }
        return
    }
    
    // 点击的是其他音频,先停止当前播放
    if isPlaying {
        audioPlayer.pause()
        isPlaying = false
    }
    
    // 更新当前播放的音频标识
    currentPlayingAudioKey = targetKey
    
    // 优先读缓存,避免重复请求
    if let cachedUrl = audioUrlCache[targetKey] {
        audioPlayer = AVPlayer(playerItem: AVPlayerItem(url: cachedUrl))
        audioPlayer.play()
        isPlaying = true
        return
    }
    
    // 无缓存则发起请求
    loadAudio(post: targetPost) { [weak self] url in
        guard let self = self, 
              // 异步请求返回时判断是否还是当前要播放的音频,避免请求回来时用户已经切歌
              self.currentPlayingAudioKey == targetKey else {
            return
        }
        // 写入缓存
        self.audioUrlCache[targetKey] = url
        self.audioPlayer = AVPlayer(playerItem: AVPlayerItem(url: url))
        self.audioPlayer.play()
        self.isPlaying = true
    }
}

4. 可选优化

可以在cellForRowAt中根据currentPlayingAudioKey同步更新单元格的播放/暂停按钮状态,避免滚动后单元格按钮显示和实际播放状态不一致;也可以监听AVPlayer的播放完成通知,自动重置播放状态。

内容的提问来源于stack exchange,提问作者EAO123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 20:54:03