iOS17新观察框架下如何监听Observable类的计算属性变化?
iOS17新观察框架下监听AVPlayer播放进度的优化方案
在iOS17的@Observable框架中,计算属性不会自动触发视图更新——因为它不依赖类内的存储属性。针对AVPlayer的currentTime监听需求,有两种更贴合新框架的方案:
方案一:手动发送变更通知
利用@Observable类自带的objectWillChange发送器,在AVPlayer的进度回调中主动通知视图更新。
@available(iOS 17.0, *) @Observable class VideoPlayerVM { private(set) var player: AVPlayer = AVPlayer() private var timeObserverToken: Any? var currentTime: CMTime { guard let currentItem = player.currentItem, let time = currentItem.currentTime().takeUnretainedValue() as? CMTime, time.isValid else { return .invalid } return time } init() { // 添加AVPlayer的定时进度监听 timeObserverToken = player.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(0.1, preferredTimescale: 600), queue: .main) { [weak self] _ in // 主动发送变更通知,触发视图重新计算currentTime self?.objectWillChange.send() } } deinit { if let token = timeObserverToken { player.removeTimeObserver(token) } } }
- 核心逻辑:通过
AVPlayer的addPeriodicTimeObserver定时捕获播放进度,每次回调时调用objectWillChange.send(),手动触发视图更新。 - 优势:完全基于新观察框架实现,无需引入Combine,代码更轻量化。
方案二:将currentTime转为存储属性
把currentTime改成存储属性,在播放进度回调中直接更新它,利用@Observable自动发布变更的特性。
@available(iOS 17.0, *) @Observable class VideoPlayerVM { private(set) var player: AVPlayer = AVPlayer() private var timeObserverToken: Any? var currentTime: CMTime = .invalid init() { timeObserverToken = player.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(0.1, preferredTimescale: 600), queue: .main) { [weak self] time in self?.currentTime = time.isValid ? time : .invalid } } deinit { if let token = timeObserverToken { player.removeTimeObserver(token) } } }
- 核心逻辑:维护一个存储属性
currentTime,在进度回调中直接更新它,@Observable会自动向视图发布变更。 - 优势:视图层无需额外处理,直接绑定
currentTime即可,代码更直观。
方案对比
- 方案一更适合需要保留计算属性逻辑的场景(比如需要额外的有效性判断或格式转换);
- 方案二更简洁,适合直接依赖
AVPlayer回调值的场景。
两种方案都比Combine方案更贴合iOS17的新观察体系,避免了Combine的发布者订阅逻辑,代码更简洁高效。
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

