简体   繁体   English

如何解决 - UndoManager 不可发送的编译器警告

[英]How to resolve - compiler warning that UndoManager is non-sendable

I have code where a set of functions need to run under a global actor context, but have undo capability.我有代码,其中一组函数需要在全局参与者上下文下运行,但具有撤消功能。 When I call them I get the following compiler warning (Xcode 14).当我打电话给他们时,我收到以下编译器警告(Xcode 14)。

Non-sendable type 'UndoManager?' passed in call to global actor 'MyActor'-isolated function cannot cross actor boundary

I understand why I get this warning, but not how to resolve it.我理解为什么会收到此警告,但不知道如何解决。

Here is some example code to illustrate the problem.这是一些示例代码来说明问题。

@globalActor actor MyActor {
    static let shared = MyActor()
}

class MyClass {

    @MyActor func doSomething(undoManager: UndoManager?) {

        // Do something here
   
        undoManager?.registerUndo(withTarget: self) { 
            $0.reverseSomething(undoManager: undoManager)
        }
    }

    @MyActor func reverseSomething(undoManager: UndoManager?) {

        // Do the reverse of something here
   
        undoManager?.registerUndo(withTarget: self) { 
            $0.doSomething(undoManager: undoManager)
        }
    }
}
 
struct MyView: View {
   @Environment(\.undoManager) private var undoManager: UndoManager?
   let myObject: MyClass

   var body: some View {
        Button("Do something") { myObject.doSomething(undoManager: undoManager) } // <- Warning here: Non-sendable type 'UndoManager?' passed in call to global actor 'MyDBActor'-isolated function cannot cross actor boundary
   }
}

What you are trying to do is keep the registration of the Undo/Redo synchronous with the actual work being done (or undone).您要做的是使撤消/重做的注册与正在完成(或撤消)的实际工作保持同步。

But you've also isolated your model into its own Actor.但是您也将 model 隔离到自己的 Actor 中。 Messages can only be passed between actors asynchronously .消息只能在参与者之间异步传递。 Swift is going to force you to deal explicitly with that. Swift 将迫使您明确处理该问题。

To synchronize with Actors, the synchronization, in this case, would happen by awaiting on a message sent to MyActor to do the work, and then awaiting on the main actor to register the undo/redo.为了与 Actor 同步,在这种情况下,同步将通过等待发送到MyActor的消息来完成工作,然后等待主要 Actor 注册撤消/重做。

So you're going to have to spawn a task to handle synchronization.所以你将不得不产生一个任务来处理同步。

In the example below I've done that.在下面的示例中,我已经做到了。 I create a task that awaits the work and then awaits the registration of the do/undo.我创建了一个等待工作的任务,然后等待执行/撤消的注册。

The problem my code introduces is that that now that whole task is asynchronous.我的代码引入的问题是,现在整个任务都是异步的。 When you call "doSomething" you're not actually doing it... you're asking the main actor to do it at some point in the future.当您调用“doSomething”时,您实际上并没有这样做……您是在要求主要演员在将来的某个时候这样做。 This may, or may not, cause problems with your code.这可能会也可能不会导致您的代码出现问题。

import SwiftUI

@globalActor actor MyActor {
    static let shared = MyActor()
    
    func reallyDoSomething() {
    }

    func reallyUndoSomething() {
    }
}

class MyClass {
    @MainActor func doSomething(undoManager: UndoManager) {
        Task {
            // Do the reverse of something here
            await MyActor.shared.reallyDoSomething()
            await MainActor.run {
                undoManager.registerUndo(withTarget: self) { this in
                    this.reverseSomething(undoManager: undoManager)
                }
            }
        }
    }

    @MainActor func reverseSomething(undoManager: UndoManager) {
        Task {
            // Do the reverse of something here
            await MyActor.shared.reallyUndoSomething()
            await MainActor.run {
                undoManager.registerUndo(withTarget: self) { this in
                    this.doSomething(undoManager: undoManager)
                }
            }
        }
    }
}
 
struct MyView: View {
   @Environment(\.undoManager) private var undoManager: UndoManager?
   let myObject: MyClass

   var body: some View {
        Button("Do something") {
            if (nil != undoManager) {
                myObject.doSomething(undoManager: undoManager!)
            }
        } // <- Warning here: Non-sendable type 'UndoManager?' passed in call to global actor 'MyDBActor'-isolated function cannot cross actor boundary
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM