0
Non-sendable type '[NSSortDescriptor]?' exiting main actor-isolated context in call to non-isolated static method 'fetch(recordType:predicate:sortDescriptions:resultsLimit:)' cannot cross actor boundary

Following code will report this error with @MainActor.

NSSortDescriptor is NSObject, '[NSSortDescriptor]?' is Non-sendable type, CloudKitUtility.fetch() is non-isolated static method, so we cannot pass sortDescriptors into CloudKitUtility.fetch() as parameter in @MainActor environment?

How can I fix this?

    @MainActor
    func fetch() async {
        let predicate = NSPredicate(value: true)
        let sortDescriptors: [NSSortDescriptor] = []
        print("fetch...")
        await MainActor.run {
            self.isLoading = true
        }
        do {
            let (items, cursor): ([Video], CKQueryOperation.Cursor?) = try await CloudKitUtility.fetch(recordType: Video.recordTypeName, predicate: predicate, sortDescriptions: sortDescriptors, resultsLimit: 100)
//            await MainActor.run {
                self.videos = items
                self.cursor = cursor
                self.isLoading = false
                print("fetch done, total = \(videos.count), has more items = \(self.hasMore)")
//            }
        } catch {
//            await MainActor.run {
                self.isLoading = false
//            }
            print(error.localizedDescription)
        }
    }
foolbear
  • 726
  • 1
  • 7
  • 19
  • `await MainActor.run` is not needed if the `func` or `class` or `struct` is wrapped with `@MainActor`, it would be best to put `@MainActor` on the `class` or `struct` where this function lives. – lorem ipsum Feb 24 '23 at 13:05
  • @loremipsum You right, use '@MainActor' or MainActor.run. I comment the MainActor.run in the code. I want to use '@MainActor' for the function, but error occurs. so the only way is using MainActor.run. But I wonder why '@MainActor' cannot. – foolbear Feb 24 '23 at 13:18
  • You are fighting concurrency, since you are altering variables that affect UI put `@MainActor` on the `class` or `struct` where this code is located. – lorem ipsum Feb 24 '23 at 13:23
  • add ```extension NSSortDescriptor: @unchecked Sendable {} extension NSPredicate: @unchecked Sendable {}``` will dismiss the warning, but I do't know is there any other deep problem. – foolbear Feb 24 '23 at 14:15

1 Answers1

0

Give this a try:

    func fetch() async throws {
        // background thread
        let predicate = NSPredicate(value: true)
        let sortDescriptors: [NSSortDescriptor] = []
        print("fetch...")
        let (items, cursor): ([Video], CKQueryOperation.Cursor?) = try await CloudKitUtility.fetch(recordType: Video.recordTypeName, predicate: predicate, sortDescriptions: sortDescriptors, resultsLimit: 100)
         Task { @MainActor in
             // main thread
             self.videos = items
             self.cursor = cursor
             print("fetch done, total = \(videos.count), has more items = \(self.hasMore)")
//      }
    }

Use like this:

@StateObject private var fetcher = Fetcher()
@State private var message = ""
@State private var loading = false
        
var body: some View {
    Button(loading ? "Cancel" : "Load") {
        loading.toggle()
    }
    .task(id: loading) {
         if !loading {
             return
         }
         do {
              await fetcher.fetch()
              message = ""
         }
         catch {
             message = error.localizedDescription
         }
         loading = false
     }
}

You can see this pattern in Apple's sample code for Meme Creator here.

malhal
  • 26,330
  • 7
  • 115
  • 133
  • YES, you right, But I just want to know why '@MainActor func fetch() async' leads to issue. – foolbear Feb 24 '23 at 14:07
  • 'Task { @MainActor in', I nerver use like this, I think it the same as 'await MainActor.run {}' that's just like the code snip I comment. – foolbear Feb 24 '23 at 14:12
  • I'm not surprised lol! Swift has so many syntax for the same thing, I hope one day they start removing syntax instead of just adding it. – malhal Feb 24 '23 at 15:24