1

我的GameWindowController(子类NSWindowController)中有以下方法:

- (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;无济于事。

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

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

4

1 回答 1

0

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

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

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

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

- (void)removeGameWindowController:(GameWindowController*)controller {
    [self.controllers performSelectorOnMainThread:@selector(removeObject:) withObject:controller waitUntilDone:NO];
}
于 2013-08-28T12:13:08.250 回答