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:
@@ -471,6 +471,222 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.connection": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Verbindung"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Connection"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.connectionUsed": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Verbindung"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Connection"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.copy": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Bericht kopieren"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Copy report"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.copyHint": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Enthält keinen Token. Kannst du unbesorgt weitergeben."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Contains no token. Safe to share."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.lastAttempt": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Letzter Abspielversuch"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Last playback attempt"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.method": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Weg"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Method"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.noServer": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Keine Serververbindung."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "No server connection."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.nothingYet": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Noch nichts abgespielt."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Nothing played yet."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.relayWarning": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Über die Plex-Vermittlung. Stark gedrosselt — große Dateien laufen darüber kaum an."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Via the Plex relay. Heavily throttled — large files barely start over it."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.source": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Quelle (ohne Token)"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Source (token removed)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.steps": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Ablauf"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Timeline"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.title": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Diagnose"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Diagnostics"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.title.label": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Titel"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Title"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"downloads.active": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
@@ -2117,6 +2333,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings.build": {
|
||||
"comment": "Zeitpunkt, zu dem der laufende Build entstanden ist",
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Build"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Build"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings.connection": {
|
||||
"extractionState": "stale",
|
||||
"localizations": {
|
||||
@@ -3180,227 +3414,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings.build": {
|
||||
"comment": "Zeitpunkt, zu dem der laufende Build entstanden ist",
|
||||
"signIn.timedOut": {
|
||||
"comment": "Die Anmeldung wurde nicht innerhalb der Gültigkeit des Codes abgeschlossen",
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Build"
|
||||
"value": "Die Anmeldung wurde nicht abgeschlossen. Versuch es noch einmal."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Build"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.title": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Diagnose"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Diagnostics"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.connection": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Verbindung"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Connection"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.noServer": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Keine Serververbindung."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "No server connection."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.relayWarning": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Über die Plex-Vermittlung. Stark gedrosselt — große Dateien laufen darüber kaum an."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Via the Plex relay. Heavily throttled — large files barely start over it."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.lastAttempt": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Letzter Abspielversuch"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Last playback attempt"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.nothingYet": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Noch nichts abgespielt."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Nothing played yet."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.title.label": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Titel"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Title"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.method": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Weg"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Method"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.connectionUsed": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Verbindung"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Connection"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.source": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Quelle (ohne Token)"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Source (token removed)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.steps": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Ablauf"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Timeline"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.copy": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Bericht kopieren"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Copy report"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diagnostics.copyHint": {
|
||||
"localizations": {
|
||||
"de": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Enthält keinen Token. Kannst du unbesorgt weitergeben."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Contains no token. Safe to share."
|
||||
"value": "Sign-in wasn't completed. Please try again."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user