Can SwiftUI View Receive a Call When Window Will Close?

I have an NSStatusBar application. This is my first in SwiftUI. And I need to know when the window is closed so that I can disable some of menu commands. I can use NSWindowDelegate with AppDelegate as follows.

import SwiftUI

@main
struct SomeApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @StateObject private var menuViewModel = MenuViewModel()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(menuViewModel)
        }
    }
}

class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
    private var menuViewModel = MenuViewModel()
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        if let window = NSApplication.shared.windows.first {
            window.setIsVisible(false)
            window.delegate = self
        }
    }
    
    func windowWillClose(_ notification: Notification) {
        menuViewModel.windowClosed = true
    }
}

When the window will close, MenuViewModel (ObservableObject) will receive a call, which I want my ContentView to receive. But, so far, it won't.

import SwiftUI

struct ContentView: View {
    var body: some View {
        ZStack {
        	...
        	...
        }
        .onReceive(statusBarViewModel.$windowClosed) { result in
        	// never called...
        }
    }
}

Can a SwiftUI View receive a call somehow when its window closes? Muchos thankos.

Answered by DTS Engineer in 801198022

@Tomato Use ScenePhase and observe the scenePhase from your WindowGroup. It would get triggered when the scene is in the foreground and interactive, inactive or isn’t currently visible in the UI.

    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { _, _ in
            switch scenePhase {
            case .active:
                print("App is active")
            case .inactive:
                print("App is inactive")
            case .background:
                print("App is in the background")
            @unknown default:
                print("Unexpected new value.")
            }
        }
    }

@Tomato Use ScenePhase and observe the scenePhase from your WindowGroup. It would get triggered when the scene is in the foreground and interactive, inactive or isn’t currently visible in the UI.

    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { _, _ in
            switch scenePhase {
            case .active:
                print("App is active")
            case .inactive:
                print("App is inactive")
            case .background:
                print("App is in the background")
            @unknown default:
                print("Unexpected new value.")
            }
        }
    }

I have the same need. There is some logic I want to run before a window closes. My SwiftUI window contains a NSViewControllerRepresentable view, and I can set the window delegate inside that NSViewController subclass and implement windowShouldClose:, but that interferes with something SwiftUI sets up and my window's resources are never freed on close. (The window goes away, but re-opening it shows the old window with whatever state it had, instead of instantiating a brand new one.)

Can SwiftUI View Receive a Call When Window Will Close?
 
 
Q