ckqueryoperation in CloudKit crashing

Use CloudKit's ckqueryoperation's recordmatchedblock in Swift 6.0, which always crashes, but works fine in Swift 5: func fetchAllRecords() async throws { let predicate = NSPredicate(format: "Topics = %@", "Integrations") let query = CKQuery(recordType: "PureMList", predicate: predicate)

    let operation = CKQueryOperation(query: query)

    operation.recordMatchedBlock = { recordID, result in
        switch result {
        case .success(let record):
            DispatchQueue.main.async {
                        // Ensure UI updates happen here
                        print("Fetched record: \(record)")
                        // Update your UI elements here
                    }
        case .failure(let error):
            // Handle the error
            print("Error fetching record with ID \(recordID): \(error)")
        }
    }


    // Ensure you're using the correct database

    publicDatabase.add(operation)
}
Answered by DTS Engineer in 811042022

If it is a crash that occurs at _dispatch_assert_queue_fail in libdispatch.dylic when you adopt Swift 6, please see here for an in-depth analysis.

Basically, Swift 6 inserted a runtime check to detect concurrency issues, and if indeed detecting an issue, it (intentionally) triggers a crash. The Swift compiler doesn't spot the issue at compile time because of "a Swift / Objective-C impedance mismatch."

To solve the issue, I'd consider two options:

  1. Use async APIs. Concretely in your case, you can replace CKQueryOperation with records(matching:inZoneWith:desiredKeys:resultsLimit:) and records(continuingMatchFrom:desiredKeys:resultsLimit:).

  2. Make the closure passed to CKQueryOperation sendable:

operation.recordMatchedBlock = { @Sendable (recordID, result) in
   ...
}

You can give it a try and follow up here if this doesn't help.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Accepted Answer

If it is a crash that occurs at _dispatch_assert_queue_fail in libdispatch.dylic when you adopt Swift 6, please see here for an in-depth analysis.

Basically, Swift 6 inserted a runtime check to detect concurrency issues, and if indeed detecting an issue, it (intentionally) triggers a crash. The Swift compiler doesn't spot the issue at compile time because of "a Swift / Objective-C impedance mismatch."

To solve the issue, I'd consider two options:

  1. Use async APIs. Concretely in your case, you can replace CKQueryOperation with records(matching:inZoneWith:desiredKeys:resultsLimit:) and records(continuingMatchFrom:desiredKeys:resultsLimit:).

  2. Make the closure passed to CKQueryOperation sendable:

operation.recordMatchedBlock = { @Sendable (recordID, result) in
   ...
}

You can give it a try and follow up here if this doesn't help.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Works, thanks

ckqueryoperation in CloudKit crashing
 
 
Q