在windowWillClose上从AppDelegate删除对NSWindowController的引用会导致崩溃

时间:2013-08-28 12:13:08

标签: macos cocoa automatic-ref-counting

我的GameWindowControllerNSWindowController的子类)中有以下方法:

- (void)windowWillClose:(NSNotification *)notification {
    AppDelegate *delegate = [NSApp delegate];
    [delegate removeGameWindowController:self];
}

AppDelegate中removeGameWindowController的代码是:

- (void)removeGameWindowController:(GameWindowController*)controller {
    [self.controllers removeObject:controller];
}

self.controllers是一个NSMutableArray,包含我的GameWindowControllers

以上代码似乎有竞争条件。当我关闭窗口时,它会随EXC_BAD_ACCESS随机崩溃,几乎每次我都会关闭所有窗口。

我的猜测是ARC在removeGameWindowController:返回之前或之后取消分配窗口控制器,使窗口留有指向控制器的悬空指针。我尝试添加controller.window.windowController = nil;无济于事。

出于某种原因,使用(BOOL)windowShouldClose:(id)sender委托方法而不是https://stackoverflow.com/a/11782844/344544中建议的方法,但不是可接受的解决方案,因为退出时不会调用它。

如何在每个窗口关闭后从控制器阵列中可靠地删除窗口控制器?是否有一些其他委托方法被调用或一些NSNotification我可以在窗口关闭后订阅哪个fire?

1 个答案:

答案 0 :(得分:0)

经过长时间的调查并在调试器中逐步运行后,我找到了问题的根源和可能的解决方案。

窗口控制器确实在removeGameWindowController:结束后的某个时刻以及包含NSWindow的所有强引用发布。如果窗口在堆栈退回到窗口本身的close调用之前被释放,则程序将在完成该函数时崩溃,因为self在这种特殊情况下是一个悬空指针。

在窗口关闭后我无法找到通知的方法,但是这种方法很可能会遇到完全相同的问题。

为了确保没有对窗口的任何引用留在堆栈的任何地方,我将从数组中删除窗口控制器排队,作为runloop上的后续事件发生:

- (void)removeGameWindowController:(GameWindowController*)controller {
    [self.controllers performSelectorOnMainThread:@selector(removeObject:) withObject:controller waitUntilDone:NO];
}