I have an app that has no startup window. So in my @main
there is no windowGroup.
var body: some Scene {
#if os(macOS)
Settings {
}
#endif
}
But in app somewhere, It is needed to create a window. (Playground runnable)
import SwiftUI
import AppKit
import PlaygroundSupport
import Foundation
class AppWindow: NSWindow, ObservableObject {
}
struct ContentView: View {
@StateObject private var viewModel: ViewModel = .init()
var body: some View {
Text(viewModel.hello)
}
}
class ViewModel: ObservableObject {
@Published var hello = "Hello"
init() {
print("init")
}
deinit {
print("deinit")
}
}
struct PlaygroundView: View {
@State private var window: AppWindow? = nil
var body: some View {
Button {
createWindow()
} label: {
Text("open window")
}
}
func createWindow() {
if let curWindow = window {
curWindow.close()
window = nil
}
let window = AppWindow(
contentRect: NSRect(x: 0, y: 0, width: 100, height: 100),
styleMask: [.titled, .closable, .miniaturizable, .resizable],
backing: .buffered,
defer: false)
window.center()
window.contentViewController = NSHostingController(rootView:
ContentView()
.frame(width: 100, height: 100, alignment: .center)
)
window.makeKeyAndOrderFront(nil)
window.isReleasedWhenClosed = true
self.window = window
}
}
PlaygroundPage.current.setLiveView(PlaygroundView())
everything is ok. The ViewModel
will print the "init" or "deinit" when the window is being opened or closed.
Until in my ContentView
, I want to do something like setFrame(..
to the window.
struct ContentView: View {
@EnvironmentObject var window: AppWindow // <--- added
@StateObject private var viewModel: ViewModel = .init()
var body: some View {
Text(viewModel.hello)
}
}
...
window.contentViewController = NSHostingController(rootView:
ContentView()
.frame(width: 100, height: 100, alignment: .center)
.environmentObject(window) // <--- added
)
...
The deinit
will not be called when the window is closed.