fix: crash on launch from BGTask handler @MainActor isolation violation

BGTaskScheduler.register(using: nil) invokes the handler on a background
queue, but the closure captured @MainActor-isolated self. Swift 6 runtime
enforces this with dispatch_assert_queue which crashed on Thread 4.

Fix: pass DispatchQueue.main as the handler queue so the callback runs
on the main queue, satisfying @MainActor isolation. Also fix expiration
handlers to capture a local Logger copy instead of accessing self.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-19 17:41:33 -06:00
parent c976ae5cb3
commit f10bc4fe59

View File

@@ -60,9 +60,12 @@ final class BackgroundSyncManager {
/// Must be called early in app lifecycle, before `applicationDidFinishLaunching` returns.
func registerTasks() {
// Register refresh task (for periodic CloudKit sync)
// using: DispatchQueue.main ensures the handler runs on the main queue,
// satisfying @MainActor isolation (using: nil invokes on a background queue,
// which crashes with dispatch_assert_queue_fail in Swift 6)
BGTaskScheduler.shared.register(
forTaskWithIdentifier: Self.refreshTaskIdentifier,
using: nil
using: DispatchQueue.main
) { [weak self] task in
guard let task = task as? BGAppRefreshTask else { return }
Task { @MainActor in
@@ -73,7 +76,7 @@ final class BackgroundSyncManager {
// Register processing task (for overnight heavy sync/cleanup)
BGTaskScheduler.shared.register(
forTaskWithIdentifier: Self.processingTaskIdentifier,
using: nil
using: DispatchQueue.main
) { [weak self] task in
guard let task = task as? BGProcessingTask else { return }
Task { @MainActor in
@@ -154,8 +157,10 @@ final class BackgroundSyncManager {
currentCancellationToken = cancellationToken
// Set up expiration handler - cancel sync gracefully
task.expirationHandler = { [weak self] in
self?.logger.warning("Background refresh task expiring - cancelling sync")
// Note: expirationHandler runs on an arbitrary queue, so avoid accessing @MainActor self
let expirationLogger = logger
task.expirationHandler = {
expirationLogger.warning("Background refresh task expiring - cancelling sync")
cancellationToken.cancel()
}
@@ -196,8 +201,9 @@ final class BackgroundSyncManager {
currentCancellationToken = cancellationToken
// Set up expiration handler - cancel sync gracefully
task.expirationHandler = { [weak self] in
self?.logger.warning("Background processing task expiring - cancelling sync")
let processingLogger = logger
task.expirationHandler = {
processingLogger.warning("Background processing task expiring - cancelling sync")
cancellationToken.cancel()
}