UndoManager 环境为零,直到视图更改 - SwiftUI

MMV*_*MMV 4 core-data cloudkit swiftui

当应用程序冷启动时, @Environment(. undoManager ) 为零,并保持为零,直到用户更改视图。当视图更改时,undoManager 将被设置并且撤消功能可用。

在下面的 gif 中,您可以看到在用户切换到新视图“焦点”然后再返回之前,撤消操作是不可用的。

以下是设置 undoManager 环境的 SwiftUI 代码:

   @Environment(\.managedObjectContext) private var viewContext
   @Environment(\.undoManager) private var undoManager
Run Code Online (Sandbox Code Playgroud)

[...]

listOfCards.task{
    viewContext.undoManager = undoManager //nil when starting from cold start
}
Run Code Online (Sandbox Code Playgroud)

例子

@main App 实例化一个 NSPersistentCloudKitContainer 并将其设置为 ManagedObjectContext

mainView
   .environment(\.managedObjectContext, persistenceController.container.viewContext)
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已经尝试过以下一些方法来解决此问题:

A) 在每个视图中添加以下内容...

.onChange(of: undoManager) { _ in
print(undoManager)
viewContext.undoManager = undoManager}
Run Code Online (Sandbox Code Playgroud)

检测何时设置 undoManager 并将其链接到 viewContext。运气不好,没有接到电话。

B)还尝试添加观察者:

private let undoObserver = NotificationCenter.default.publisher(for: .NSUndoManagerCheckpoint)


.onReceive(undoObserver, perform: { _ in
print(undoManager)
viewContext.undoManager = undoManager
})
Run Code Online (Sandbox Code Playgroud)

同样不幸的是,它唯一起作用的就是转到另一个视图并返回,然后 UndoManager 设置正确。有任何想法吗?我错过了一些明显的东西吗?

FPP*_*FPP 5

好吧,这个很好的扩展已经View帮了我很多了: Hosting Controller When using iOS 14 @main

extension View {
    func withHostingWindow(_ callback: @escaping (NSWindow?) -> Void) -> some View {
        self.background(HostingWindowFinder(callback: callback))
    }
}

struct HostingWindowFinder: NSViewRepresentable {
    typealias NSViewType = NSView
    
    var callback: (NSWindow?) -> ()
    
    func makeNSView(context: Context) -> NSView {
        let view = NSView()
        DispatchQueue.main.async { [weak view] in
            self.callback(view?.window)
        }
        return view
    }
    
    func updateNSView(_ nsView: NSView, context: Context) {
    }
}
Run Code Online (Sandbox Code Playgroud)

这样你就可以做这样的事情:

@State private var undoManager: UndoManager? 
Run Code Online (Sandbox Code Playgroud)

替换环境撤消管理器。然后在body

.withHostingWindow({ window in                                  // set the undo manager from window
    undoManager = window?.undoManager
})
Run Code Online (Sandbox Code Playgroud)

对该闭包的前几次调用将给出nilfor undoManager,但在发生任何交互之前,undoManager将正确设置 var 。