iphaaw
iphaaw

Reputation: 7204

SwiftUI: Closing opened window on macOS causes crash

I can open a new window, but if I close it using the window's close button then my app crashes.

import SwiftUI

struct ContentView: View
{
    var body: some View
    {
        Button(action: {openMyWindow()},
               label: {Image(systemName: "paperplane")})
            .padding()
    }
}

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

struct WindowView: View
{
    var body: some View
    {
        Text("Hello World")
            .padding()
    }
}

@main

struct Open_WindowApp: App 
{
    var body: some Scene 
    {
        WindowGroup 
        {
            ContentView()
        }
    }
}

I think I need to keep my windowRef active, but how do I do this?

Upvotes: 2

Views: 667

Answers (2)

mr. fixit
mr. fixit

Reputation: 1552

  1. declare windowRef outside the scope of openMyWindow()

  2. if the window already exists, bring to front, don't make another.

  3. keep the window from being dealloc'd on close, either

    • windowRef.isReleasedWhenClosed = false (shown below) (documentation), OR

    • someGlobalWindowController = NSWindowController(window: w)

    var windowRef: NSWindow? 
    func openMyWindow()
    {
        if let curWindow = windowRef {
            curWindow.makeKeyAndOrderFront(nil)
            return
        }
        let w = NSWindow(
            contentRect: NSRect(x: 100, y: 100, width: 100, height: 600),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        w.contentView = NSHostingView(rootView: WindowView())
        w.makeKeyAndOrderFront(nil)
        w.isReleasedWhenClosed = false // <--- important
        windowRef = w
    }

Upvotes: 3

Asperi
Asperi

Reputation: 257711

We need to keep reference to window, try the following

struct ContentView: View
{
    @State private var windowRef: NSWindow?

    var body: some View
    {
        Button(action: {openMyWindow()},
               label: {Image(systemName: "paperplane")})
            .padding()
    }

    func openMyWindow()
    {
        // handle previously opened window here somehow if needed
        guard windowRef == nil else { return }

        windowRef = NSWindow(
            contentRect: NSRect(x: 100, y: 100, width: 100, height: 600),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        windowRef?.contentView = NSHostingView(rootView: WindowView())
        windowRef?.makeKeyAndOrderFront(nil)
    }

}

Upvotes: 1

Related Questions