You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何延迟触发AVPlayer前进按钮事件以解决多次点击卡顿问题?

解决AVPlayer快速点击前进按钮卡顿的防抖方案

这问题我做音乐类APP时也碰到过,快速连续点前进按钮会触发多次网络请求+AVPlayerItem初始化,直接把主线程堵得死死的,卡顿简直没法忍。你说的“等停止点击2秒再执行”其实就是开发里常用的**防抖(Debounce)**逻辑,刚好能完美解决这个问题,结合你的Swift 4.2和Xcode 10环境,给你两种靠谱的实现方式:

方式一:用Timer实现防抖

这种方式逻辑直观,非常适合UI交互场景:

  1. 先在你的ViewController里定义一个Timer变量,用来控制延迟执行:
private var forwardDebounceTimer: Timer?
  1. 重写前进按钮的点击事件处理方法,每次点击都重置定时器:
@IBAction func forwardButtonTapped(_ sender: UIButton) {
    // 先取消之前未执行的定时器,避免重复触发
    forwardDebounceTimer?.invalidate()
    
    // 创建新定时器,2秒后执行真正的切换逻辑
    forwardDebounceTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { [weak self] _ in
        self?.switchToNextSong()
    }
}
  1. 把原来的切换歌曲逻辑抽成单独的方法,让定时器触发时调用:
private func switchToNextSong() {
    // 这里放你从Firebase获取下一首URL、创建AVPlayerItem的逻辑
    fetchNextSongURLFromFirebase { [weak self] songURL in
        guard let self = self, let url = songURL else { return }
        
        // 确保在主线程更新UI/AVPlayer
        DispatchQueue.main.async {
            let nextItem = AVPlayerItem(url: url)
            self.player.replaceCurrentItem(with: nextItem)
            self.player.play() // 如果需要自动播放的话
        }
    }
}

// 假设你原来从Firebase获取URL的方法是这样的(根据你的实际代码调整)
private func fetchNextSongURLFromFirebase(completion: @escaping (URL?) -> Void) {
    let firestore = Firestore.firestore()
    firestore.collection("your-songs-collection").document("next-song-doc").getDocument { snapshot, error in
        if let err = error {
            print("获取歌曲URL失败:\(err.localizedDescription)")
            completion(nil)
            return
        }
        
        guard let urlStr = snapshot?.data()?["song_url"] as? String, let url = URL(string: urlStr) else {
            completion(nil)
            return
        }
        completion(url)
    }
}

方式二:用DispatchWorkItem实现防抖

如果更喜欢用GCD的方式,也可以用DispatchWorkItem来实现,效果完全一样:

  1. 定义一个WorkItem变量:
private var forwardWorkItem: DispatchWorkItem?
  1. 修改点击事件处理:
@IBAction func forwardButtonTapped(_ sender: UIButton) {
    // 取消之前的任务
    forwardWorkItem?.cancel()
    
    // 创建新任务,包裹切换逻辑
    let workItem = DispatchWorkItem { [weak self] in
        self?.switchToNextSong()
    }
    forwardWorkItem = workItem
    
    // 延迟2秒执行
    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: workItem)
}

关键注意点

  • 一定要用[weak self]避免循环引用,不管是Timer的闭包还是DispatchWorkItem,都要弱引用self,防止内存泄漏
  • 每次点击都要取消之前的延迟任务,这样只有用户停止点击满2秒后,才会执行最后一次的切换请求
  • 网络请求和AVPlayerItem的创建尽量不要阻塞主线程,Firebase的回调本身是在后台队列的,所以切换AVPlayer的操作要切回主线程

这样改造后,不管用户怎么快速点前进按钮,只有当他停手2秒后,才会触发一次歌曲切换,避免了重复的网络请求和AVPlayer初始化,卡顿问题自然就解决了。

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

火山引擎 最新活动