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

调用removeObserver无法移除AVPlayer.currentItem绑定的观察者求助

问题解决:AVPlayer循环观察者无法移除的修复方案

核心问题原因

你使用的闭包形式addObserver(forName:object:queue:using:)会返回一个独立的观察者对象,但你调用removeObserver(self, ...)是错误的——这个观察者并非self,而是方法返回的NSObjectProtocol实例。没保存这个实例的引用,就没法精准移除旧观察者。

修复步骤

  1. 新增观察者引用存储
    添加一个@State变量,用来保存每个AVPlayerItem对应的观察者,确保能定位到要移除的对象:

    @State var players: [AVPlayer] = [myAVPlayers]
    @State var selectedIndex: Int = 0
    // 存储AVPlayerItem到观察者的映射关系
    @State var playerObservers: [AVPlayerItem: NSObjectProtocol] = [:]
    
  2. 切换视频时先清理旧观察者
    在更新selectedIndex之前,先处理上一个视频的观察者:

    DragGesture()
        .onEnded { _ in
            // 1. 获取上一个视频的AVPlayerItem
            let previousPlayerItem = players[selectedIndex].currentItem
            // 2. 取出对应观察者并移除
            if let previousObserver = playerObservers[previousPlayerItem] {
                NotificationCenter.default.removeObserver(previousObserver)
                playerObservers.removeValue(forKey: previousPlayerItem)
            }
            
            // 3. 更新selectedIndex到新值(此处需根据你的滑动逻辑替换为实际的newIndex)
            selectedIndex = newIndex
            
            // 4. 为新视频添加循环观察者
            let currentPlayerItem = players[selectedIndex].currentItem
            guard let item = currentPlayerItem else { return }
            let observer = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: item, queue: .main) { [weak self] _ in
                guard let self = self else { return }
                // 修正原代码错误:players[selectedIndex]是AVPlayer,直接调用seek和play
                self.players[self.selectedIndex].seek(to: .zero)
                self.players[self.selectedIndex].play()
            }
            // 5. 将新观察者存入映射表
            playerObservers[item] = observer
        }
    
  3. 页面销毁时清理所有观察者
    避免内存泄漏,在View销毁时移除剩余观察者:

    .onDisappear {
        for observer in playerObservers.values {
            NotificationCenter.default.removeObserver(observer)
        }
        playerObservers.removeAll()
    }
    

关键注意事项

  • 闭包形式添加的观察者,必须用返回的实例调用removeObserver(_:),不能用removeObserver(self)。
  • 闭包内使用[weak self]避免循环引用,防止内存泄漏。
  • 每次添加新观察者前,务必先移除旧的,避免重复注册导致多次触发回调。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:35:23