我的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;
无济于事。
出于某种原因,使用(BOOL)windowShouldClose:(id)sender
委托方法而不是https://stackoverflow.com/a/11782844/344544中建议的方法,但不是可接受的解决方案,因为退出时不会调用它。
如何在每个窗口关闭后从控制器阵列中可靠地删除窗口控制器?是否有一些其他委托方法被调用或一些NSNotification我可以在窗口关闭后订阅哪个fire?
答案 0 :(得分:0)
经过长时间的调查并在调试器中逐步运行后,我找到了问题的根源和可能的解决方案。
窗口控制器确实在removeGameWindowController:
结束后的某个时刻以及包含NSWindow
的所有强引用发布。如果窗口在堆栈退回到窗口本身的close
调用之前被释放,则程序将在完成该函数时崩溃,因为self
在这种特殊情况下是一个悬空指针。
在窗口关闭后我无法找到通知的方法,但是这种方法很可能会遇到完全相同的问题。
为了确保没有对窗口的任何引用留在堆栈的任何地方,我将从数组中删除窗口控制器排队,作为runloop上的后续事件发生:
- (void)removeGameWindowController:(GameWindowController*)controller {
[self.controllers performSelectorOnMainThread:@selector(removeObject:) withObject:controller waitUntilDone:NO];
}