swift 动态创建和删除NSWindow

vbopmzt1  于 2023-02-07  发布在  Swift
关注(0)|答案(1)|浏览(253)

我希望以编程方式创建(和销毁)NSWindows

class Wins: NSObject, NSWindowDelegate {

    var windows = Set<NSWindow>()

    func createWindow() {
        
        let newWindow = NSWindow(contentRect: .init(origin: .zero, size: .init(width: 300, height: 300)),
                                 styleMask: NSWindow.StyleMask(rawValue: 0xf),
                                 backing: .buffered,
                                 defer: false)
        newWindow.title = "New Window"
        newWindow.isOpaque = false
        newWindow.isMovableByWindowBackground = true

        newWindow.backgroundColor = NSColor(calibratedHue: 0, saturation: 1.0, brightness: 0, alpha: 0.7)
        newWindow.makeKeyAndOrderFront(nil)

        let windowController = NSWindowController()
        windowController.window = newWindow

        windows.insert(newWindow)
    }

    func closeAll() {
        for win in windows {
            windows.remove(win)
            win.close()
        }
    }

}

虽然上面的代码可以工作,但是关闭的窗口永远不会被释放,并且会在内存中不断堆积。
如果我移除windowController赋值,当我尝试使用EXC_BAD_ACCESS关闭窗口时,应用会崩溃,使用分析器,我可以看到窗口实际上已被解除分配:
An Objective-C message was sent to a deallocated 'NSWindow' object (zombie) at address...
因此,我认为windowController示例是罪魁祸首,并且永远不会被销毁。
如何为以编程方式创建的窗口实现正确的NSWindow生命周期?

esyap4oy

esyap4oy1#

由于历史原因,NSWindow的解除分配有点复杂,从NSWindow.close()的文档中可以看到:
如果窗口设置为关闭时释放,则在当前事件完成后会向对象发送释放消息。对于NSWindow对象,默认设置为关闭时释放,而对于NSPanel对象,默认设置为不释放。可以使用isReleasedWhenClosed属性更改默认行为。
来自isReleasedWhenClosed的文档:
如果窗口在关闭后自动释放,则此属性的值为true;如果只是将其从屏幕中删除,则返回false。
NSWindow的默认值为true;NSPanel的默认值是false。2然而,对于窗口控制器拥有的窗口,关闭时释放被忽略。3释放NSWindow对象的另一个策略是让它的委托在接收到windowShouldClose(_:)消息时自动释放它。
如果您拥有该窗口,则isReleasedWhenClosed应为false,并且可以删除窗口控制器。

func createWindow() {
    
    let newWindow = NSWindow(contentRect: .init(origin: .zero, size: .init(width: 300, height: 300)),
                             styleMask: NSWindow.StyleMask(rawValue: 0xf),
                             backing: .buffered,
                             defer: false)
    newWindow.isReleasedWhenClosed = false
    newWindow.title = "New Window"
    newWindow.isOpaque = false
    newWindow.isMovableByWindowBackground = true

    newWindow.backgroundColor = NSColor(calibratedHue: 0, saturation: 1.0, brightness: 0, alpha: 0.7)
    newWindow.makeKeyAndOrderFront(nil)

    windows.insert(newWindow)
}

相关问题