繁体   English   中英

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

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

我有代码,其中一组函数需要在全局参与者上下文下运行,但具有撤消功能。 当我打电话给他们时,我收到以下编译器警告(Xcode 14)。

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

我理解为什么会收到此警告,但不知道如何解决。

这是一些示例代码来说明问题。

@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
   }
}

您要做的是使撤消/重做的注册与正在完成(或撤消)的实际工作保持同步。

但是您也将 model 隔离到自己的 Actor 中。 消息只能在参与者之间异步传递。 Swift 将迫使您明确处理该问题。

为了与 Actor 同步,在这种情况下,同步将通过等待发送到MyActor的消息来完成工作,然后等待主要 Actor 注册撤消/重做。

所以你将不得不产生一个任务来处理同步。

在下面的示例中,我已经做到了。 我创建了一个等待工作的任务,然后等待执行/撤消的注册。

我的代码引入的问题是,现在整个任务都是异步的。 当您调用“doSomething”时,您实际上并没有这样做……您是在要求主要演员在将来的某个时候这样做。 这可能会也可能不会导致您的代码出现问题。

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