【问题标题】:MacOS Cocoa, why am i not able to close windows?MacOS Cocoa,为什么我无法关闭窗口?
【发布时间】:2022-01-24 18:28:53
【问题描述】:

我正在使用 XCode Swift,使用带有 Storyboard 的 Cocoa,我需要能够以编程方式创建和关闭自己的窗口。

为了尽可能简单地重复这个问题,我从一个空的故事板项目开始,只更改 ViewController.swift 中的 viewDidLoad

override func viewDidLoad() {
    super.viewDidLoad()
    
    let rect = NSRect( x:500, y:500, width:800, height:500 )
    let mask = NSWindow.StyleMask( arrayLiteral: .closable, .miniaturizable, .resizable, .titled )
    let win = NSWindow( contentRect: rect, styleMask: mask, backing: .buffered, defer: false )
    
    win.orderFront( win )
}

应用程序运行,并打开两个窗口。较小的来自故事板,可以毫无问题地关闭,但是当我关闭我创建的较大窗口时,应用程序在 appDelegate 中崩溃

线程 1:EXC_BAD_ACCESS(代码=1,地址=0x20)

我假设我在这里做了一些愚蠢的事情 - 我错过了什么?

我发现如果我设置了

win.isReleasedWhenClosed = false

问题消失了,但是我认为内存没有被释放。

我还发现,如果我在关闭数组之前将窗口句柄附加到数组,问题也会消失:

private var broken_windows [NSWindow] = []

public func windowShouldClose( _ sender: NSWindow ) -> Bool {
    
    broken_windows.append( sender )
    return true
}

然而这个数组在某种程度上是完全不可触碰的,并且在窗口关闭后任何试图访问它的成员都会导致应用程序崩溃。

【问题讨论】:

  • 崩溃发生在应用程序委托的哪个位置?您尚未显示您的应用委托代码。
  • 我没有应用程序委托代码,这是一个空项目,如上所述,仅由我在问题中发布的代码修改。我希望我必须在应用程序委托中实现一些东西才能正确关闭窗口,我不知道在这里放什么代码 - 这是我的问题。
  • 当我说“我没有应用程序委托代码”时,我的意思是我在启动项目时没有修改 Xcode IDE 提供的默认模板。我会在这里发布,但我认为在评论中不合适。我并不是说没有应用程序委托。当应用程序崩溃时,lldb 指向 class AppDelegate: NSObject, NSApplicationDelegate { 声明,并给我一个我无法遵循的堆栈跟踪。

标签: swift macos cocoa


【解决方案1】:

在您更新的代码中,仅保留该窗口是因为您通过self.win 持有一个strong reference。如果你使用weak var win: NSWindow?,那么在窗口关闭后self.win 将为零。所以,设置isReleasedWhenClosed = false 似乎是一个有效的解决方案。

【讨论】:

  • 请看我最初的问题 - 设置isReleasedWhenClosed = false 仅用于防止应用程序崩溃,但它会使窗口挂在内存中。如果我持有对窗口的强引用,则应用程序不会在委托中崩溃,如上所述,但一旦我删除引用,它就会崩溃。使用弱引用无效,关闭窗口时应用仍然崩溃。
  • 这不是真的——我创建了一个示例项目并粘贴了您的代码,添加了win.isReleasedWhenClosed = false,当两个窗口都关闭时,即使没有实例变量或数组中的任何引用,应用程序也不会崩溃。我正在运行 macOS 12.1。
  • 也许在您实际的非示例项目中,您还有其他东西对窗口有很强的引用?
猜你喜欢
  • 1970-01-01
  • 2011-09-26
  • 1970-01-01
  • 2020-05-12
  • 1970-01-01
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多