fix: use sublayer instead of replacing NSView backing layer to prevent autorelease crash

- PlayerNSView: AVPlayerLayer as sublayer (not layer= replacement)
  NSView internally manages a sublayer array; replacing the backing
  layer directly causes dangling refs during autorelease pool drain
- cleanup(): only pause + remove observers, no replaceCurrentItem
  CoreMedia internal state gets corrupted when item is replaced
  during view teardown; let it release naturally with deinit
This commit is contained in:
yumoqing 2026-06-22 00:47:05 +08:00
parent aa19ab9799
commit f14d47b5c8
2 changed files with 14 additions and 10 deletions

View File

@ -388,12 +388,13 @@ final class PlayerBridge: ObservableObject {
/// app 退
func cleanup() {
player.pause()
if let obs = timeObserver { player.removeTimeObserver(obs); timeObserver = nil }
itemStatusObserver?.invalidate(); itemStatusObserver = nil
playbackStatusObserver?.invalidate(); playbackStatusObserver = nil
if let token = endObserverToken { NotificationCenter.default.removeObserver(token); endObserverToken = nil }
player.pause()
player.replaceCurrentItem(with: nil)
// replaceCurrentItem(with: nil)
// playerItem player CoreMedia
}
deinit {

View File

@ -54,26 +54,29 @@ struct VideoPlayerRepresentable: NSViewRepresentable {
}
class PlayerNSView: NSView {
private let playerLayer = AVPlayerLayer()
override init(frame: NSRect) {
super.init(frame: frame)
wantsLayer = true
let playerLayer = AVPlayerLayer()
playerLayer.videoGravity = .resizeAspect
layer = playerLayer
}
required init?(coder: NSCoder) {
fatalError()
}
required init?(coder: NSCoder) { fatalError() }
override func layout() {
super.layout()
(layer as? AVPlayerLayer)?.frame = bounds
// playerLayer sublayer init addSublayer
// wantsLayer=true layer
if playerLayer.superlayer !== layer {
layer?.addSublayer(playerLayer)
}
playerLayer.frame = bounds
}
var player: AVPlayer? {
get { (layer as? AVPlayerLayer)?.player }
set { (layer as? AVPlayerLayer)?.player = newValue }
get { playerLayer.player }
set { playerLayer.player = newValue }
}
}
#endif