I tried to make as simple example as possible using Swift 6 to produce this problem which I am having difficulty to solve:
func getValue() async -> Int { 0 }
func getValuePublisher() -> AnyPublisher<Int, Never> {
Future { continuation in
Task {
let value = await getValue()
continuation(.success(value))
}
}.eraseToAnyPublisher()
}
This will produce a compile time error (Swift 6 only) saying
Passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure
The bottom line is to convert an existing async operation to a publisher in any way. I am sure I just need to use more suitable tools for the job, but I am having trouble finding a correct tool to use.
How can I best to deal with this situation?
Note: The async method is existing and can not be changed. It simply needs to be incorporated somehow into publisher pipeline.
In terms of general description of the error, see the Swift user documentation. The general idea to avoid this sort of error is to make sure the Task
is isolated to the same actor that this function uses.
So, for example, you can isolate the function to a global actor:
func getValue() async -> Int { 0 }
@MainActor // or use any custom global actor, if you want
func getValuePublisher() -> AnyPublisher<Int, Never> {
Future { continuation in
Task {
let value = await getValue()
continuation(.success(value))
}
}.eraseToAnyPublisher()
}