Updating an app to use strict concurrency is not compiling in Swift 6 with strict concurrency enabled. I am getting the following error in Xcode Version 16.0 (16A242d).
private func queryHealthKit() async throws -> (
[HKSample]?, [HKDeletedObject]?, HKQueryAnchor?
) {
try await withCheckedThrowingContinuation { continuation in
// Create a predicate that returns only samples created within the last 24 hours.
let endDate = Date()
let startDate = endDate.addingTimeInterval(-24.0 * 60.0 * 60.0)
let datePredicate = HKQuery.predicateForSamples(
withStart: startDate, end: endDate, options: [.strictStartDate, .strictEndDate])
// Create the query.
let query = HKAnchoredObjectQuery(
type: caffeineType,
predicate: datePredicate,
anchor: anchor,
limit: HKObjectQueryNoLimit
) { (_, samples, deletedSamples, newAnchor, error) in
// When the query ends, check for errors.
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume(returning: (samples, deletedSamples, newAnchor))
}
}
store.execute(query)
}
}
The error is on
** continuation.resume(returning: (samples, deletedSamples, newAnchor))
**
and the error is
Task-isolated value of type '([HKSample]?, [HKDeletedObject]?, HKQueryAnchor?)' passed as a strongly transferred parameter; later accesses could race. How to solve this error?
Just so we’re clear, we’re talking about the Updating an app to use strict concurrency sample code which is associated with WWDC 2024 Session 10169 Migrate your app to Swift 6.
When I build that with Xcode 16.0 I see the error you’re reporting. I think Xcode is correct here, and the sample is in error. To explore this, I hacked up the code to look like this:
private func queryHealthKit2() async throws -> HKSample {
try await withCheckedThrowingContinuation { continuation in
… unchanged …
// Create the query.
let query = HKAnchoredObjectQuery(
type: caffeineType,
predicate: datePredicate,
anchor: anchor,
limit: HKObjectQueryNoLimit
) { (_, samples, deletedSamples, newAnchor, error) in
// When the query ends, check for errors.
if let error {
continuation.resume(throwing: error)
} else {
let s = samples!.first!
continuation.resume(returning: s)
// ^ Sending 's' risks causing data races
// task-isolated 's' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses
}
}
store.execute(query)
}
}
IMPORTANT This code isn’t meant to work! I hacked it up to uncover exactly what the compiler is complaining about. That’s why the method name is queryHealthKit2()
.
This gives a nicer error. The issue is that s
is of type HKSample
, which isn’t sendable. The value was created in one isolation domain (the query callback) and we’re trying to pass it to a different isolation domain (the queryHealthKit()
async actor method).
Given that, I’d appreciate you filing a bug against the sample. Please post your bug number, just for the record.
As to what you can do about this, it depends on your goals. If you just want the sample to compile, so you can explore other parts of it, replace the problematic line with this:
continuation.resume(returning: (nil, nil, nil))
If you want the code to actually work, things get more complex. And it might be easier for us to discuss your real issue rather than this sample. Assuming that your really isn’t isn’t with HealthKit! (-:
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"