Search code examples
macosswiftuiwindow

SwiftUI: Run code when window closed macOS


I have opened my window in the traditional way, but I want to run some code when the window is closed by clicking the close box (red button). Is there a good way of doing this?

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

Solution

  • Great question.. I struggled on that a time ago as well.

    You can make your AppDelegate or class conform to NSWindowDelegate protocol.

    Then pass self as the delegate of the window

    myWindow.delegate = self
    

    And implement following function to be notified by the closing action

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

    Edit:

    When you are using SwiftUI life cycle, you can add an AppDelegate. You can also implement your own WindowManager class. Here is an example:

    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")
        }
    }
    

    Create and hold that class in your struct _: App and open Windows via this Manager.

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