The issue is that builder
and session
are remoted to the MainActor
however not Sendable
. You can’t name nonisolated async
strategies on it as a result of that may find yourself sending it off the primary actor.
It’s best to name beginCollection
in a non-isolated technique, so there are not any actor hops that sends non-sendable values. It’s best to solely assign the builder and session again to the occasion properties (sending them again to the primary actor) after you might be accomplished with them. Because of region-based isolation, Swift understands that that is your final time utilizing the builder and session within the non-isolated technique, so they’re protected to be despatched off.
If you happen to ship them again to the primary actor earlier than that, you might be basically sharing the occasion between the primary actor and the non-isolated code after that, which in fact will not be protected with non-sendable values.
// major actor remoted model so as to simply name from a view
func startWatchWorkout(_ identify: String, _ startDate: Date) async {
await startWatchWorkoutImpl(identify, startDate)
}
non-public nonisolated func startWatchWorkoutImpl(_ identify: String, _ startDate: Date) async {
do {
let configuration = HKWorkoutConfiguration()
configuration.activityType = .traditionalStrengthTraining
// be aware that I'm not assigning to self.session and self.builder right here
let session = attempt HKWorkoutSession.make(healthStore: retailer, configuration: configuration)
let builder = session?.associatedWorkoutBuilder()
builder?.dataSource = HKLiveWorkoutDataSource(healthStore: retailer, workoutConfiguration: configuration)
session?.startActivity(with: startDate)
attempt await builder?.beginCollection(at: startDate)
await setSessionAndBuilder(session, builder)
} catch {
// ...
}
}
// assigning the properties needs to be accomplished in a major actor remoted context
non-public func setSessionAndBuilder(_ s: HKWorkoutSession?, _ b: HKLiveWorkoutBuilder?) {
session = s
builder = b
}