onmyway133 / blog

🍁 What you don't know is what you haven't learned
https://onmyway133.com/
MIT License
675 stars 33 forks source link

How to avoid crash when closing NSWindow for agent macOS app #312

Open onmyway133 opened 5 years ago

onmyway133 commented 5 years ago
class ClosableWindow: NSWindow {
    override func close() {
        self.orderOut(NSApp)
    }
}

let window = ClosableWindow(
    contentRect: rect,
    styleMask: [.titled, .closable],
    backing: .buffered,
    defer: false
}

window.makeKeyAndOrderFront(NSApp)

The reason is that window is released upon closed if it is not owned by NSWindowController, or we can use releasedWhenClosed

The value of this property is YES if the window is automatically released after being closed; NO if it’s simply removed from the screen.

The default for NSWindow is YES; the default for NSPanel is NO. Release when closed, however, is ignored for windows owned by window controllers. Another strategy for releasing an NSWindow object is to have its delegate autorelease it on receiving a windowShouldClose: message.

vojtabohm commented 1 year ago

Good snippet. Any idea why the window is still being released after setting releasedWhenClosed = false? The window is not inside a windowController.

Also - even when the window (stored in mainWindow property) is released and I create a new one mainWindow = createNewMainWindow() and then try to present it again, the app crashes on EXC_BAD_ACCESS (accessing the released property. This is weird, doesn't the property get overriden with the new window in memory?

haren724 commented 10 months ago

Good snippet. Any idea why the window is still being released after setting releasedWhenClosed = false? The window is not inside a windowController.

Also - even when the window (stored in mainWindow property) is released and I create a new one mainWindow = createNewMainWindow() and then try to present it again, the app crashes on EXC_BAD_ACCESS (accessing the released property. This is weird, doesn't the property get overriden with the new window in memory?

Your NSWindow is released by ARC, which may be irrelevant to releasedWhenClosed. It seems that this such property has conflicted with ARC in Swift. Always set this to false to avoid app crash.

vojtabohm commented 3 months ago

It seems that this such property has conflicted with ARC in Swift.

You might be right with this. close() seems to both release and also remove the window from the NSApplication.shared.windows list which removes the strong reference and ARC performs another release. Which causes a crash because you cannot release an already released object.

Always set this to false to avoid app crash

If this is really the convention for programmatic windows then I blame Apple for not thoroughly documenting this fact.

vojtabohm commented 3 months ago

My hunch was right. I created a Stack Overflow post, and a friendly, knowledgeable person confirmed it. Link