Understanding the warning and how to fix it: Non-sendable cannot cross actor boundary

Hi all,

I'm testing the first beta for iOS 16.4 and Xcode 14.3 and I'm getting these warnings that I kind of understand, but I don't know and I haven't found how to solve them.

For example this code that is just a simplified example:

@MainActor class ATextModel: ObservableObject {

    @Published private(set) var record: CKRecord?

    func getData() async {
        let database = CKContainer.default().publicCloudDatabase
        let query = CKQuery(recordType: "Test", predicate: NSPredicate(value: true))

        do {
            let results = try await database.records(matching: query)
            self.record = try results.matchResults.first?.1.get()
        } catch {
            print("Error: \(error.localizedDescription)")
        }
    }
}

Is giving me 2 warnings:

Non-sendable type '(matchResults: [(CKRecord.ID, Result<CKRecord, any Error>)], queryCursor: CKQueryOperation.Cursor?)' returned by call from main actor-isolated context to non-isolated instance method 'records(matching:inZoneWith:desiredKeys:resultsLimit:)' cannot cross actor boundary

Non-sendable type 'CKQuery' exiting main actor-isolated context in call to non-isolated instance method 'records(matching:inZoneWith:desiredKeys:resultsLimit:)' cannot cross actor boundary

Does someone has a hint on how I should do this now?

This might be just an error in the beta, but I don't really think that.

Post not yet marked as solved Up vote post of iturrajoel Down vote post of iturrajoel
5k views
Add a Comment

Replies

I have a similar situation. I have a CKMethods protocol which I use in a number of View Controllers. I get warnings about CKRecord not being sendable. What I've been doing to try to fix it is to move the functions into the View Controllers. But now I'm stuck with this among other warnings.

let matchTemp = try await database.records(for: recIDs) 

Non-sendable type '[CKRecord.ID : Result<CKRecord, any Error>]' returned by call from main actor-isolated context to non-isolated instance method 'records(for:desiredKeys:)' cannot cross actor boundary

Here's another one.

let results =  try await database.modifyRecords(saving: records, deleting: [], savePolicy: .allKeys, atomically: false)

Non-sendable type '[CKRecord]' exiting main actor-isolated context in call to non-isolated instance method 'modifyRecords(saving:deleting:savePolicy:atomically:)' cannot cross actor boundary

  • The warning was caused by a bug in the Xcode beta, but this will be an issue in the future, so I hope that Apple will share the "right way" to do this, or probably they will make everything Sendable in CK.

  • The more I look into this, the more I disagree with you. CKRecord is not sendable. The way to go, I think, is to create a struct with the fields from the CKRecords. Then pass the struct but make sure it's sendable. I have started to do this and it's clearing warnings. I have a CKMethods protocol. I think the way to go is to pass the stunt into the protocol's methods and get a struct from the protocol. Converting from CKRecord to Struct and from Struct to CKRecord.

  • How does CKRecord to Struct solve the problem? You cross the CK interface, providing CKRecord, CKSubscription, etc and it is that interface that you must await on. It seems your other comment "@unchecked Sendable" is the only solution? Or perhaps you could add extensions to CloudKit to define some 'shadow functions' that mark the non-sendable parameters as isolated; but, this could get tedious and won't work on returned values.

Add a Comment

The issue is that CKRecord is not sendable, so the worry is that different threads could change the same CKRecord object, thus causing problems. There is a dangerous way to turn off the warnings.

extension CKRecord: @unchecked Sendable {

}

Telling the compiler to turn off the warnings. In my app, as I have mentioned before, I have a CKMethods protocol that other View Controllers use. I have never had an issue with CKRecord not being sendable before this compiler update. I am working on a new update to my app and have turned done the above dangerous move, but I welcome a solution that fixes the issue while keeping why code basically in tact.

  • Turned on that is.

Add a Comment

same for me, and more stranger in Xcode 15 beta warning disappears... :(

The reason it goes away is that Apple now makes CKRecord conform to Sendable https://developer.apple.com/documentation/cloudkit/ckrecord?changes=latest_minor

Add a Comment