Search code examples
objective-ccrashnspanel

Why does my app crash when an NSPanel is closed by pressing Escape?


I have an NSPanel in my app that is crashing the app (EXC_BAD_ACCESS in main()) whenever it is closed by pressing the Escape key. Closing it any other way (File > Close, Cmd-W, clicking the red close button) works fine.

The panel is shown by instantiating its window controller from the storyboard. A reference to the window controller is stored in a dictionary. In the view controller's -viewWillDisappear the window controller is removed from the dictionary.

    wc = [[NSStoryboard storyboardWithName:@"Main" bundle:nil] instantiateControllerWithIdentifier:kSBIDPreviewWindowController];
    // ...
    [windowsOfType addObject:wc];
    // ...
    [wc showWindow:self];

On close:

-(void)viewDidDisappear {
    // ...
    if ([windowsOfType containsObject:winController]) {
        [windowsOfType removeObject:winController];
    }
}

The crash is apparently triggered by removing the window controller from the dictionary. If I keep it, it won't crash.

Some further info:

  • The panel contains (only) a WebView.
  • The panel's Release When Closed checkbox is off.
  • All other options are default (except Hide on Deactivate which is on.)

I can't find the problem with the debugger as the crash happens in main(), ie. after the window has been closed.

Any idea what could be causing this?

And, more generally, which technique should I use to debug such a situation?

Updated 2018-02-19:

Enabling Zombies got me the message -[NSWindowController setNextResponder:]: message sent to deallocated instance 0x60000028a9b0. So something is talking to the window controller after it has been released. Since that isn't my code directly (I'm not even subclassing NSWindowController, and not making any calls to the window controller anywhere), the question remains: What is different when the window is closed by hitting Escape as compared to other methods (like Cmd-W)?

Updated 2018-02-19 #2:

Instruments gave an interesting result. Apparently the WebView which I have on the panel tries to process the pressing of the Escape key after the panel has been closed/deallocated (triggered in my case by the view controller's -viewDidDisappear.)

The Zombie source is -[WebResponderChainSink detach], called (via some intermediate calls) by -[WebHTMLView keyDown:].

It looks like the WebView is not correctly passing on the keypress or something...? Could this mean that a WebView on a panel is a bad idea?


Solution

  • I found the solution to avoid this type of crash; you have to delay the release of the last reference to the window controller until after the current event processing is done (by using dispatch_async(), for example.)

    That allows the WebView to do its thing with the keypress.