Absturz beim Abspielen, und die Annahme dahinter
Der Crashlog vom Gerät:
_dispatch_assert_queue_fail
_swift_task_checkIsolatedSwift
MainActor.assumeIsolated
VLCPlayerEngine.mediaPlayerStateChanged(_:)
VLCKit input_thread_Events
Im Code stand als Begründung für assumeIsolated, VLCKit stelle seine
Rückrufe über die Hauptwarteschlange zu. Das ist falsch — es ruft den
Delegaten von seinem eigenen Input-Thread. Die App brach deshalb hart
ab, sobald VLC den ersten Zustandswechsel meldete, also unmittelbar
beim Drücken auf Play.
Alle drei Delegat-Methoden springen jetzt mit Task { @MainActor in }
sauber hinüber. Die Reihenfolge bleibt erhalten: die Aufgaben werden aus
demselben Thread nacheinander eingereiht.
Dieselbe Annahme steckte im AVPlayer-Motor in den KVO-Beobachtern —
KVO meldet auf dem Thread, der die Änderung ausgelöst hat, und AVPlayer
ändert seinen Zustand auch aus internen Threads. Ebenfalls umgestellt.
Die beiden Rückrufe mit ausdrücklichem queue: .main behalten
assumeIsolated: dort ist die Annahme belegt statt geraten, und der
Zeitbeobachter feuert viermal je Sekunde.
Dazu die Anmeldung: Plex führt den Rücksprung über forwardUrl nicht
zuverlässig aus. Auf dem iPad landet der Browser nach dem Anmelden auf
watch.plex.tv und bleibt stehen — der Token liegt bereit, aber die App
wartete auf einen Rückruf, der nie kam. Das Fenster wird jetzt geöffnet,
ohne darauf zu warten; parallel wird im Sekundentakt beim Server
nachgefragt. Der Rücksprung ist damit eine Annehmlichkeit, keine
Voraussetzung.
132 Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -189,7 +189,11 @@ public final class AVPlayerEngine: VideoPlayerEngine {
|
||||
private func observePlayer() {
|
||||
observations.append(
|
||||
player.observe(\.timeControlStatus, options: [.new]) { [weak self] player, _ in
|
||||
MainActor.assumeIsolated {
|
||||
// Kein `assumeIsolated`: KVO meldet auf dem Thread, der die
|
||||
// Änderung ausgelöst hat, und AVPlayer ändert seinen Zustand
|
||||
// auch aus internen Threads. Genau dieselbe Annahme hat die App
|
||||
// im VLC-Motor zum Absturz gebracht.
|
||||
Task { @MainActor in
|
||||
guard let self else { return }
|
||||
switch player.timeControlStatus {
|
||||
case .playing: self.state = .playing
|
||||
@@ -207,6 +211,9 @@ public final class AVPlayerEngine: VideoPlayerEngine {
|
||||
forInterval: CMTime(seconds: 0.25, preferredTimescale: 600),
|
||||
queue: .main
|
||||
) { [weak self] time in
|
||||
// Hier ist `assumeIsolated` belegt statt geraten: die Warteschlange
|
||||
// steht eine Zeile darüber. Viermal je Sekunde eine Aufgabe
|
||||
// einzureihen wäre unnötiger Aufwand.
|
||||
MainActor.assumeIsolated {
|
||||
guard let self, time.isNumeric else { return }
|
||||
self.continuation?.yield(.timeChanged(.seconds(time.seconds)))
|
||||
@@ -217,7 +224,9 @@ public final class AVPlayerEngine: VideoPlayerEngine {
|
||||
private func observe(item: AVPlayerItem) {
|
||||
observations.append(
|
||||
item.observe(\.status, options: [.new]) { [weak self] item, _ in
|
||||
MainActor.assumeIsolated {
|
||||
// Siehe oben: auch dieser Rückruf kommt nicht verlässlich vom
|
||||
// Hauptthread.
|
||||
Task { @MainActor in
|
||||
guard let self else { return }
|
||||
switch item.status {
|
||||
case .failed:
|
||||
@@ -241,6 +250,7 @@ public final class AVPlayerEngine: VideoPlayerEngine {
|
||||
object: item,
|
||||
queue: .main
|
||||
) { [weak self] _ in
|
||||
// Ebenfalls ausdrücklich auf der Hauptwarteschlange.
|
||||
MainActor.assumeIsolated {
|
||||
guard let self else { return }
|
||||
self.state = .ended
|
||||
|
||||
Reference in New Issue
Block a user