SwiftUI: закрытие открытого окна на macOS вызывает сбой

#macos #swiftui #window

#macos #свифтуи #окно

Вопрос:

Я могу открыть новое окно, но если я закрою его с помощью кнопки закрытия окна, тогда мое приложение выйдет из строя.

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

Я думаю, мне нужно сохранить свой windowRef активным, но как мне это сделать?

Комментарии:

1. пожалуйста, укажите стек потока сбоев

Ответ №1:

  1. объявить windowRef вне области openMyWindow()
  2. если окно уже существует, выведите его на передний план, не создавайте другое.
  3. не допускайте освобождения окна при закрытии
    • windowRef.isReleasedWhenClosed = false (показано ниже) (документация), ИЛИ
    • 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
    }

 

Ответ №2:

Нам нужно сохранить ссылку на window, попробуйте следующее

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

}
 

Комментарии:

1. это не компилируется, потому что последние две строки openMyWindow() должны развернуть необязательные. как только мы это исправим, он запустится, но только до тех пор, пока вы не нажмете кнопку 2-го раза, затем произойдет сбой (EXC_BAD_ACCESS) в операторе guard