79669231

Date: 2025-06-17 14:10:46
Score: 0.5
Natty:
Report link

Async Solution

You can combine pawello222's answer with Mojitaba Hosseini's answer from another question on how to make synchronous tasks to synchronously process asynchronous code on app termination event, like so:

NotificationCenter.default.addObserver(forName: UIApplication.willTerminateNotification, object: nil, queue: .main) { [self] _ in
    Task.synchronous { [self] in
        await asyncWork()
    }
}

Extension Code

Task.synchronous extension (credit to Mojitaba Hosseini):

extension Task where Failure == Error {
    /// Performs an async task in a sync context.
    ///
    /// - Note: This function blocks the thread until the given operation is finished. The caller is responsible for managing multithreading.
    static func synchronous(priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success) {
        let semaphore = DispatchSemaphore(value: 0)

        Task(priority: priority) {
            defer { semaphore.signal() }
            return try await operation()
        }

        semaphore.wait()
    }
}

Caveat

If you use actors in your code at all, awaiting any actor method or variable will cause the Task to never complete/to be killed. Instead, you should resolve and store any actor variables locally, then capture them in the Task closure to use them without any actor access waiting.

Example:

let peripheral = await localPeripheral
        
peripheralTerminateNotification = NotificationCenter.default.addObserver(forName: UIApplication.willTerminateNotification, object: nil, queue: .main) { [self] _ in
    Task.synchronous { [self] in
        await stop(peripheral: peripheral)
    }
}
Reasons:
  • Blacklisted phrase (1): another question
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: Rollersteaam