Search code examples
swiftasync-awaitcloudkit

Swift continuation doesn't make await continue


I'm using async/await with CloudKit, and I want to query for Items. So I wrote the following:

private func getItems() async throws -> [Item] {
    // let predicate = NSPredicate(value: true)
    let predicate = NSPredicate(format: "id != %@", "blah")
    let sort = NSSortDescriptor(key: "creationDate", ascending: false)
    let query = CKQuery(recordType: "Item", predicate: predicate)
    query.sortDescriptors = [sort]
    print("Let's go!")

    let items: [Item] = await withCheckedContinuation { continuation in
        let op = CKQueryOperation(query: query)
        op.recordMatchedBlock = { (recordId, result) in
            print("recordMatchedBlock")
        }

        op.queryResultBlock = { result in
            print("queryCompletionBlock: Jobs done!")
            continuation.resume(returning: [])
        }

        db.add(op)
    }
    print("All done!")

    return items
}

If I used the true-predicate it would give me a failure on recordName (a field I don't have on Item) was missing, hence the other predicate.

Anyway, this prints "Let's go!" nicely, prints "recordMatchedBlock" for each Item, and then "Jobs done!". At that point the continuation should resume, and items should get the [] value. But "All done!" is never printed.

Why is "All done!" never printed? Why does the continuation not make the await continue?


Solution

  • The Xcode13b2 release notes say:

    The async Task APIs in macOS, watchOS, and tvOS differ from the async Task APIs in iOS. As a result, Task API calls on Actor objects in multi-platform projects may cause async functions to hang at a suspension point. (79378627)

    That' it! That fit the bill perfectly. So for now I'll keep developing this on iOS and expect the hang to be ironed out.