SwiftUI:运行 window 关闭 macOS 时的代码

SwiftUI: Run code when window closed macOS

我已经以传统方式打开了 window,但我想在 window 通过单击关闭框(红色按钮)关闭时 运行 一些代码。有什么好的方法吗?

func openMyWindow()
{
    myWindow = (NSWindow(
    contentRect: NSRect(x: 100, y: 100, width: 100, height: 600),
    styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false))
    myWindow!.contentView = NSHostingView(rootView: MyWindowView())
        myWindow!.makeKeyAndOrderFront(nil)
}

好问题..我之前也曾在这个问题上挣扎过。

您可以让您的 AppDelegate 或 class 符合 NSWindowDelegate 协议。

然后通过self作为window

的代表
myWindow.delegate = self

并实现以下功能以通过关闭操作通知

func windowShouldClose(_ sender: NSWindow) -> Bool
{}

编辑:

当你使用SwiftUI生命周期时,你可以添加一个AppDelegate。您也可以实现自己的 WindowManager class。这是一个例子:

class WindowManager : NSObject, NSWindowDelegate {
    var popUpWindow : NSWindow? = nil
    
    override init() {}
    
    func openMyWindow()
    {
        popUpWindow = (NSWindow(
        contentRect: NSRect(x: 100, y: 100, width: 100, height: 600),
        styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false))
        popUpWindow!.contentView = NSHostingView(rootView: PopUpView())
        popUpWindow!.makeKeyAndOrderFront(nil)
        popUpWindow?.delegate = self
    }
    
    func windowShouldClose(_ sender: NSWindow) -> Bool
    {
        print("Window will close")
        return true
    }
}

struct PopUpView : View {
    var body: some View {
        Text("This is a new popup view")
    }
}

在您的 struct _: App 中创建并保持 class 并通过此管理器打开 Windows。

@main
struct macSwiftUICycleApp: App {
    let persistenceController = PersistenceController.shared

    let windowManager : WindowManager = WindowManager() //<< Here keep the instance of your WindowManager
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
                .onAppear {
                    windowManager.openMyWindow() //<< Just a test to open another window on startup
                }
        }
    }
}

如果您想要 运行 的代码独立于上下文,那么最简单的解决方案是替换 window 和 运行 您的代码的关闭操作,例如

func openMyWindow()
{
    // ... other your code

    myWindow!.contentView = NSHostingView(rootView: MyWindowView())

    let closeButton = myWindow!.standardWindowButton(.closeButton)  // << !!
    closeButton?.action = #selector(NSWindow.doMyClose(_:))           // << !!

    myWindow!.makeKeyAndOrderFront(nil)
}

extension NSWindow {
    @objc
    func doMyClose(_ sender: Any?) {
        // ... run your code here

        self.close()  // << make standard window close

        // ... or here 
    }
}

如果你想用捕获的变量执行一些闭包,那么方法是相同的,但使用自定义处理程序 class 将保存 window 和闭包来执行。