GlobalActor指令不能保证该演员会调用功能
假设我已经定义了一个全球演员:
@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
print(\(Thread.isMainThread) /// Prints true when called from undo stack
undoManager?.registerUndo(withTarget: self) {
$0.doSomething(undoManager: UndoManager)
}
}
}
假设代码从swiftui视图中调用:
struct MyView: View {
@Environment(\.undoManager) private var undoManager: UndoManager?
let myObject: MyClass
var body: some View {
Button("Do something") { myObject.doSomething(undoManager: undoManager) }
}
}
请注意,当操作被撤销时,“反向反向” func是打电话给主要线程。防止这种情况包裹在任务中的正确方法是正确的吗?如:
@MyActor func reverseSomething(undoManager: UndoManager) {
// Do the reverse of something here
print(\(Thread.isMainThread) /// Prints true
undoManager?.registerUndo(withTarget: self) {
Task { $0.doSomething(undoManager: UndoManager) }
}
}
Assuming I have defined a global actor:
@globalActor actor MyActor {
static let shared = MyActor()
}
And I have a class, in which a couple of methods need to act under this:
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
print(\(Thread.isMainThread) /// Prints true when called from undo stack
undoManager?.registerUndo(withTarget: self) {
$0.doSomething(undoManager: UndoManager)
}
}
}
Assume the code gets called from a SwiftUI view:
struct MyView: View {
@Environment(\.undoManager) private var undoManager: UndoManager?
let myObject: MyClass
var body: some View {
Button("Do something") { myObject.doSomething(undoManager: undoManager) }
}
}
Note that when the action is undone the 'reversing' func it is called on the MainThread. Is the correct way to prevent this to wrap the undo action in a task? As in:
@MyActor func reverseSomething(undoManager: UndoManager) {
// Do the reverse of something here
print(\(Thread.isMainThread) /// Prints true
undoManager?.registerUndo(withTarget: self) {
Task { $0.doSomething(undoManager: UndoManager) }
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
令我惊讶的是,编译器不会在同步的非分离上下文(即关闭)中引起全局演员为“ myActor”的实例方法的警告。看来,编译器被隔离方法中的闭合语法混淆了。
无论如何,您可以将其包裹在
任务
中,并且应该在适当的演员上运行:就说是说,我发现了从背景中使用它时不稳定的
undomanager
行为线程(即,不在主要演员上)。因此,尤其是因为撤消/重做是通常是从UI(在主线程上)启动的行为,所以我将其保留在主线程上,并且仅在另一个演员上运行所需的工作。例如:
现在,这是一个人为的例子(对于这个简单的事情,我们不会在全球演员上只有一个数组),但希望它说明了这个想法。
或者,您可以使用非全球演员:
I am surprised that the compiler does not generate a warning about calling a global actor 'MyActor'-isolated instance method in a synchronous nonisolated context (i.e. the closure). It would appear that the compiler is confused by the closure syntax within an actor isolated method.
Anyway, you can wrap it in a
Task
and it should run that on the appropriate actor:That having been said, I have found erratic
UndoManager
behavior when using it from a background thread (i.e., not on the main actor).So, especially because undo/redo is behavior generally initiated from the UI (on the main thread), I would keep it on the main thread, and only run the desired work on another actor. E.g.:
Now, this is a somewhat contrived example (for something this simple, we wouldn't have a simply array on a global actor), but hopefully it illustrates the idea.
Or, you can use a non-global actor: