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

子类化AVPlayer时,是否有比通知中心更直接的播放结束监听方式?

替代AVPlayer全局通知的播放结束监听方案

AVPlayer/AVQueuePlayer并没有提供可直接重写的方法来捕获播放结束事件,但你可以用以下几种更严谨、低耦合的方式替代全局通知:

1. 为每个AVPlayerItem单独绑定通知监听

在子类中管理每个添加的item的通知监听,只响应自己管辖的item的结束事件,避免全局通知的广播干扰:

class FancyAVPlayer: AVQueuePlayer {
    
    private var observationTokens = [NSObjectProtocol]()
    
    override init(items: [AVPlayerItem]) {
        super.init(items: items)
        items.forEach(setupItemObservers)
    }
    
    override func insert(_ item: AVPlayerItem, after afterItem: AVPlayerItem?) {
        super.insert(item, after: afterItem)
        setupItemObservers(item)
    }
    
    override func remove(_ item: AVPlayerItem) {
        super.remove(item)
        removeItemObservers(item)
    }
    
    private func setupItemObservers(_ item: AVPlayerItem) {
        let token = NotificationCenter.default.addObserver(
            forName: .AVPlayerItemDidPlayToEndTime,
            object: item,
            queue: .main
        ) { [weak self] _ in
            self?.handleItemEnded(item)
        }
        observationTokens.append(token)
    }
    
    private func removeItemObservers(_ item: AVPlayerItem) {
        observationTokens.removeAll { token in
            if let observer = token as? NSNotificationObserver, observer.object as? AVPlayerItem == item {
                NotificationCenter.default.removeObserver(observer)
                return true
            }
            return false
        }
    }
    
    private func handleItemEnded(_ item: AVPlayerItem) {
        print("AVPlayer subclass, item \(item) ended")
        // 这里可以扩展自定义回调逻辑,比如闭包回调、代理方法
    }
    
    deinit {
        observationTokens.forEach(NotificationCenter.default.removeObserver)
    }
}

2. 使用Combine框架实现响应式监听(Swift 5.1+)

利用Combine的发布者机制,监听currentItem变化并绑定结束通知,代码更简洁且自动管理生命周期:

import Combine

class FancyAVPlayer: AVQueuePlayer {
    
    private var cancellables = Set<AnyCancellable>()
    
    override init(items: [AVPlayerItem]) {
        super.init(items: items)
        setupCombineObservers()
    }
    
    override func insert(_ item: AVPlayerItem, after afterItem: AVPlayerItem?) {
        super.insert(item, after: afterItem)
        setupCombineObservers()
    }
    
    private func setupCombineObservers() {
        self.publisher(for: \.currentItem)
            .compactMap { $0 }
            .flatMap { item in
                NotificationCenter.default.publisher(
                    for: .AVPlayerItemDidPlayToEndTime,
                    object: item
                )
            }
            .sink { [weak self] _ in
                self?.handleItemEnded()
            }
            .store(in: &cancellables)
    }
    
    private func handleItemEnded() {
        print("AVPlayer subclass, playback ended via Combine")
    }
    
    deinit {
        cancellables.removeAll()
    }
}

3. 利用边界时间观察者监听播放结束点

通过设置播放进度的边界点,当播放到接近结束时间时触发回调:

class FancyAVPlayer: AVQueuePlayer {
    
    private var boundaryObservers = [Any]()
    
    override func insert(_ item: AVPlayerItem, after afterItem: AVPlayerItem?) {
        super.insert(item, after: afterItem)
        setupBoundaryObserver(for: item)
    }
    
    private func setupBoundaryObserver(for item: AVPlayerItem) {
        // 稍微延后结束时间,避免因时间精度问题提前触发
        let endTime = CMTimeAdd(item.duration, CMTimeMakeWithSeconds(0.1, preferredTimescale: 1000))
        let times = [NSValue(time: endTime)]
        
        let observer = addBoundaryTimeObserver(forTimes: times, queue: .main) { [weak self] in
            guard let self = self, self.currentItem == item else { return }
            self.handleItemEnded()
        }
        boundaryObservers.append(observer)
    }
    
    private func handleItemEnded() {
        print("AVPlayer subclass, playback ended via boundary observer")
    }
    
    deinit {
        boundaryObservers.forEach { removeTimeObserver($0) }
    }
}

需要注意的是,AVPlayer的设计中并没有开放可重写的播放结束回调方法,苹果更倾向于通过通知、KVO或Combine这类响应式机制来暴露播放状态变化。上面的方案都比全局通知更合理,因为它们只关注当前播放器管理的媒体项,减少了不必要的耦合。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 08:37:32