There is a protocol GarageFetchable defined in a framework
I have no control over this framework.
Protocol contains a function fetchGarage that accepts a completion handler
Problem:
I would like to execute a swift concurrent function and then call the completion handler
When I call the completion and pass value I get the warning: Capture of 'completion' with non-sendable type '(Garage) -> ()' in a @Sendable closure
Environment:
I have set the build setting Strict Concurrency Checking to Complete
Xcode 14.0 beta 6 (14A5294g)
macOS 13.0 Beta (22A5331f)
Question:
What is the right way / approach to call the completion handler after an async function?
Code:
struct Car {
var name: String
}
struct Garage {
let name: String
let cars: [Car]
}
func fetchCars() async throws -> [Car] {
try await Task.sleep(nanoseconds: 2_000_000_000)
let cars = [Car(name: "aaa"),
Car(name: "bbbb")]
return cars
}
//This is defined in the framework and I have no control over this function
protocol GarageFetchable {
func fetchGarage(completion: @escaping (Garage) -> ())
}
struct DataStore: GarageFetchable {
func fetchGarage(completion: @escaping (Garage) -> ()) {
Task {
let cars = try? await fetchCars()
let garage = Garage(name: "Garage1", cars: cars ?? [])
completion(garage) //Warning: Capture of 'completion' with non-sendable type '(Garage) -> ()' in a `@Sendable` closure
}
}
}
We don't currently have a better answer than just calling the completion handler from the Task you created. Hopefully you can encourage this framework to adopt async/await sooner rather than later. At the very least, it should declare the completion handler function as @Sendable, which would eliminate that warning.
We are hoping to do some implementation work to preserve structured concurrency for this pattern across @objc interfaces, but it probably will not be straightforward to take advantage of that in your code, especially if it's doing completion handlers with native Swift function types instead of ObjC blocks.