【问题标题】:SwiftUI: Closing opened window on macOS causes crashSwiftUI:在 macOS 上关闭打开的窗口会导致崩溃
【发布时间】:2021-03-14 21:52:11
【问题描述】:

我可以打开一个新窗口,但如果我使用窗口的关闭按钮关闭它,我的应用程序就会崩溃。

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 处于活动状态,但我该怎么做呢?

【问题讨论】:

  • 请包含崩溃线程的堆栈

标签: macos swiftui window


【解决方案1】:

我们需要保持对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)
    }

}

【讨论】:

  • 这不会编译,因为openMyWindow() 的最后两行需要解包可选。一旦我们解决了这个问题,它就会运行,但只有在您第二次单击该按钮之前,它才会在保护语句处崩溃(EXC_BAD_ACCESS)
【解决方案2】:
  1. openMyWindow()范围之外声明windowRef

  2. 如果窗口已经存在,就放到前面,不要再做一个。

  3. 在关闭时保持窗口不被释放

    • windowRef.isReleasedWhenClosed = false(如下所示)(documentation),或者

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 2021-07-24
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多