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:
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user