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

AVPlayer播放结束通知非注册线程触发时如何保障UI操作线程安全

解决方案

线程保障的两种实现方式

两种方案都可以实现弹窗在主线程执行,优先推荐第二种带队列参数的监听方式:

  • 方案1:保留现有selector监听方式,在presentAlert方法内部手动派发至主队列执行
    代码示例:
    @objc func presentAlert() {
        DispatchQueue.main.async {
            // 此处写弹窗创建、展示的代码
            let alert = UIAlertController(title: "播放完成", message: nil, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "确定", style: .default))
            self.present(alert, animated: true)
        }
    }
    

    注意:所有UI相关操作必须放在主队列的闭包内,不能漏写。

  • 方案2:改用addObserver(forName:object:queue:using:)方法,直接传入主队列,回调默认在主线程执行
    代码示例:
    // 将observer引用存为类属性,后续销毁观察者时需要用到
    private var playEndObserver: NSObjectProtocol?
    
    // 监听代码
    playEndObserver = NotificationCenter.default.addObserver(
        forName: .AVPlayerItemDidPlayToEndTime,
        object: currentPlayItem, // 这里要填当前正在播放的AVPlayerItem实例,不要传nil
        queue: OperationQueue.main,
        using: { [weak self] _ in
            guard let self = self else { return }
            // 直接编写弹窗代码,已经运行在主线程
            let alert = UIAlertController(title: "播放完成", message: nil, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "确定", style: .default))
            self.present(alert, animated: true)
        }
    )
    

额外修复弹窗触发时机异常的问题

你遇到的重播中途触发、其他页面弹出的问题,除了线程因素外,还有两处明显的配置错误需要修正:

  1. 现有监听代码的object参数传了nil,会接收全局所有AVPlayerItem的播放结束通知,包括其他页面的播放实例、你之前播放过的旧资源的通知,必须把这个参数设置为当前你正在监听的AVPlayerItem实例。
  2. 必须在页面销毁、切换播放资源的时候移除对应观察者:
    • 如果用selector方式:NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: currentPlayItem)
    • 如果用block方式:if let observer = playEndObserver { NotificationCenter.default.removeObserver(observer) }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:18:04