簡體   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