diff --git a/ios/Runner/MpvPlayer/MpvPlayerCore.swift b/ios/Runner/MpvPlayer/MpvPlayerCore.swift index c8992da3..12cbd2a6 100644 --- a/ios/Runner/MpvPlayer/MpvPlayerCore.swift +++ b/ios/Runner/MpvPlayer/MpvPlayerCore.swift @@ -49,6 +49,7 @@ class MpvPlayerCore: NSObject { weak var delegate: MpvPlayerDelegate? private(set) var isInitialized = false + private var isDisposing = false // Flag to prevent race conditions during disposal // HDR settings private var hdrEnabled = true // User preference for HDR @@ -147,7 +148,8 @@ class MpvPlayerCore: NSObject { mpv_set_wakeup_callback( mpv, { ctx in - let core = Unmanaged.fromOpaque(ctx!).takeUnretainedValue() + guard let ctx = ctx else { return } // Safe guard instead of force unwrap + let core = Unmanaged.fromOpaque(ctx).takeUnretainedValue() core.readEvents() }, UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())) @@ -308,7 +310,7 @@ class MpvPlayerCore: NSObject { private func readEvents() { queue.async { [weak self] in - guard let self = self, let mpv = self.mpv else { return } + guard let self = self, !self.isDisposing, let mpv = self.mpv else { return } while true { let event = mpv_wait_event(mpv, 0) @@ -487,12 +489,16 @@ class MpvPlayerCore: NSObject { // MARK: - Cleanup func dispose() { + // Set disposing flag first to prevent race conditions with event callbacks + isDisposing = true + NotificationCenter.default.removeObserver(self) let mpvHandle = mpv mpv = nil - queue.sync { + // Use async to avoid blocking the main thread (prevents deadlock) + queue.async { if let handle = mpvHandle { mpv_set_wakeup_callback(handle, nil, nil) mpv_terminate_destroy(handle) diff --git a/lib/mpv/player/player_native.dart b/lib/mpv/player/player_native.dart index e129ade3..5aa076e6 100644 --- a/lib/mpv/player/player_native.dart +++ b/lib/mpv/player/player_native.dart @@ -400,8 +400,8 @@ class PlayerNative implements Player { _checkDisposed(); await _ensureInitialized(); - // Show the video layer - await _methodChannel.invokeMethod('setVisible', {'visible': true}); + // Show the video layer (use error-handled method) + await setVisible(true); // Set HTTP headers for Plex authentication and profile if (media.headers != null && media.headers!.isNotEmpty) {